1 /*
2 * Copyright (C) 2021 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 "pastedata_record_napi.h"
16 #include "pastedata_napi.h"
17 #include "pasteboard_common.h"
18 #include "napi_common.h"
19 #include "pasteboard_hilog.h"
20 #include "paste_data_record.h"
21 #include "async_call.h"
22 #include "pasteboard_js_err.h"
23
24 using namespace OHOS::MiscServices;
25 using namespace OHOS::Media;
26
27 namespace OHOS {
28 namespace MiscServicesNapi {
29 static thread_local napi_ref g_pasteDataRecord = nullptr;
30 const int ARGC_TYPE_SET0 = 0;
31 const int ARGC_TYPE_SET1 = 1;
32 constexpr int32_t MIMETYPE_MAX_SIZE = 1024;
33
PasteDataRecordNapi()34 PasteDataRecordNapi::PasteDataRecordNapi() : env_(nullptr), wrapper_(nullptr)
35 {
36 }
37
~PasteDataRecordNapi()38 PasteDataRecordNapi::~PasteDataRecordNapi()
39 {
40 napi_delete_reference(env_, wrapper_);
41 }
42
NewInstanceByRecord(napi_env env,napi_value & instance,const std::shared_ptr<MiscServices::PasteDataRecord> & record)43 bool PasteDataRecordNapi::NewInstanceByRecord(
44 napi_env env, napi_value &instance, const std::shared_ptr<MiscServices::PasteDataRecord> &record)
45 {
46 NAPI_CALL_BASE(env, PasteDataRecordNapi::NewInstance(env, instance), false);
47 PasteDataRecordNapi *obj = nullptr;
48 napi_status status = napi_unwrap(env, instance, reinterpret_cast<void **>(&obj));
49 if ((status != napi_ok) || (obj == nullptr)) {
50 return false;
51 }
52 obj->value_ = record;
53 obj->JSFillInstance(env, instance);
54 return true;
55 }
56
NewHtmlTextRecordInstance(napi_env env,const std::string & text,napi_value & instance)57 bool PasteDataRecordNapi::NewHtmlTextRecordInstance(napi_env env, const std::string &text, napi_value &instance)
58 {
59 NAPI_CALL_BASE(env, PasteDataRecordNapi::NewInstance(env, instance), false);
60 PasteDataRecordNapi *obj = nullptr;
61 napi_status status = napi_unwrap(env, instance, reinterpret_cast<void **>(&obj));
62 if ((status != napi_ok) || (obj == nullptr)) {
63 return false;
64 }
65 obj->value_ = PasteboardClient::GetInstance()->CreateHtmlTextRecord(text);
66 obj->JSFillInstance(env, instance);
67 return true;
68 }
69
NewPlainTextRecordInstance(napi_env env,const std::string & text,napi_value & instance)70 bool PasteDataRecordNapi::NewPlainTextRecordInstance(napi_env env, const std::string &text, napi_value &instance)
71 {
72 NAPI_CALL_BASE(env, PasteDataRecordNapi::NewInstance(env, instance), false);
73 PasteDataRecordNapi *obj = nullptr;
74 napi_status status = napi_unwrap(env, instance, reinterpret_cast<void **>(&obj));
75 if ((status != napi_ok) || (obj == nullptr)) {
76 return false;
77 }
78 obj->value_ = PasteboardClient::GetInstance()->CreatePlainTextRecord(text);
79 obj->JSFillInstance(env, instance);
80 return true;
81 }
82
NewPixelMapRecordInstance(napi_env env,const std::shared_ptr<PixelMap> pixelMap,napi_value & instance)83 bool PasteDataRecordNapi::NewPixelMapRecordInstance(
84 napi_env env, const std::shared_ptr<PixelMap> pixelMap, napi_value &instance)
85 {
86 if (pixelMap == nullptr) {
87 PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "pixelMap is nullptr.");
88 return false;
89 }
90
91 NAPI_CALL_BASE(env, PasteDataRecordNapi::NewInstance(env, instance), false);
92 PasteDataRecordNapi *obj = nullptr;
93 napi_status status = napi_unwrap(env, instance, reinterpret_cast<void **>(&obj));
94 if ((status != napi_ok) || (obj == nullptr)) {
95 PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "unwrap failed.");
96 return false;
97 }
98 obj->value_ = PasteboardClient::GetInstance()->CreatePixelMapRecord(pixelMap);
99 obj->JSFillInstance(env, instance);
100 return true;
101 }
102
NewUriRecordInstance(napi_env env,const std::string & text,napi_value & instance)103 bool PasteDataRecordNapi::NewUriRecordInstance(napi_env env, const std::string &text, napi_value &instance)
104 {
105 NAPI_CALL_BASE(env, PasteDataRecordNapi::NewInstance(env, instance), false);
106 PasteDataRecordNapi *obj = nullptr;
107 napi_status status = napi_unwrap(env, instance, reinterpret_cast<void **>(&obj));
108 if ((status != napi_ok) || (obj == nullptr)) {
109 return false;
110 }
111 obj->value_ = PasteboardClient::GetInstance()->CreateUriRecord(OHOS::Uri(text));
112 obj->JSFillInstance(env, instance);
113 return true;
114 }
115
NewWantRecordInstance(napi_env env,const std::shared_ptr<OHOS::AAFwk::Want> want,napi_value & instance)116 bool PasteDataRecordNapi::NewWantRecordInstance(
117 napi_env env, const std::shared_ptr<OHOS::AAFwk::Want> want, napi_value &instance)
118 {
119 if (!want) {
120 return false;
121 }
122
123 NAPI_CALL_BASE(env, PasteDataRecordNapi::NewInstance(env, instance), false);
124 PasteDataRecordNapi *obj = nullptr;
125 napi_status status = napi_unwrap(env, instance, reinterpret_cast<void **>(&obj));
126 if ((status != napi_ok) || (obj == nullptr)) {
127 return false;
128 }
129 obj->value_ = PasteboardClient::GetInstance()->CreateWantRecord(want);
130 obj->JSFillInstance(env, instance);
131 return true;
132 }
133
NewKvRecordInstance(napi_env env,const std::string & mimeType,const std::vector<uint8_t> & arrayBuffer,napi_value & instance)134 bool PasteDataRecordNapi::NewKvRecordInstance(
135 napi_env env, const std::string &mimeType, const std::vector<uint8_t> &arrayBuffer, napi_value &instance)
136 {
137 NAPI_CALL_BASE(env, PasteDataRecordNapi::NewInstance(env, instance), false);
138 PasteDataRecordNapi *obj = nullptr;
139 napi_status status = napi_unwrap(env, instance, reinterpret_cast<void **>(&obj));
140 if ((status != napi_ok) || (obj == nullptr)) {
141 PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "unwrap failed");
142 return false;
143 }
144 obj->value_ = PasteboardClient::GetInstance()->CreateKvRecord(mimeType, arrayBuffer);
145 obj->JSFillInstance(env, instance);
146 return true;
147 }
148
SetNamedPropertyByStr(napi_env env,napi_value & instance,const char * propName,const char * propValue)149 void PasteDataRecordNapi::SetNamedPropertyByStr(
150 napi_env env, napi_value &instance, const char *propName, const char *propValue)
151 {
152 if (propName == nullptr || propValue == nullptr) {
153 return;
154 }
155 napi_value prop = nullptr;
156 if (napi_create_string_utf8(env, propValue, NAPI_AUTO_LENGTH, &prop) == napi_ok) {
157 napi_set_named_property(env, instance, propName, prop);
158 }
159 }
160
SetNapiKvData(napi_env env,std::shared_ptr<MineCustomData> customData)161 napi_value PasteDataRecordNapi::SetNapiKvData(napi_env env, std::shared_ptr<MineCustomData> customData)
162 {
163 if (customData == nullptr) {
164 return nullptr;
165 }
166 napi_value jsCustomData = nullptr;
167 napi_create_object(env, &jsCustomData);
168 auto itemData = customData->GetItemData();
169 PASTEBOARD_HILOGD(PASTEBOARD_MODULE_CLIENT, "size = %{public}d.", static_cast<uint32_t>(itemData.size()));
170 for (auto &item : itemData) {
171 void *data = nullptr;
172 napi_value arrayBuffer = nullptr;
173 size_t len = item.second.size();
174 NAPI_CALL(env, napi_create_arraybuffer(env, len, &data, &arrayBuffer));
175 if (memcpy_s(data, len, reinterpret_cast<const void *>(item.second.data()), len) != 0) {
176 return nullptr;
177 }
178 NAPI_CALL(env, napi_set_named_property(env, jsCustomData, item.first.c_str(), arrayBuffer));
179 PASTEBOARD_HILOGD(PASTEBOARD_MODULE_CLIENT, "mimeType = %{public}s.", item.first.c_str());
180 }
181 return jsCustomData;
182 }
183
GetNativeKvData(napi_env env,napi_value napiValue)184 std::shared_ptr<MineCustomData> PasteDataRecordNapi::GetNativeKvData(napi_env env, napi_value napiValue)
185 {
186 napi_valuetype valueType = napi_undefined;
187 NAPI_CALL(env, napi_typeof(env, napiValue, &valueType));
188 NAPI_ASSERT(env, valueType == napi_object, "Wrong argument type. Object expected.");
189
190 napi_value mimeTypes = nullptr;
191 NAPI_CALL(env, napi_get_property_names(env, napiValue, &mimeTypes));
192 uint32_t mimeTypesNum = 0;
193 NAPI_CALL(env, napi_get_array_length(env, mimeTypes, &mimeTypesNum));
194
195 PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "mimeTypesNum = %{public}u", mimeTypesNum);
196 std::shared_ptr<MineCustomData> customData = std::make_shared<MineCustomData>();
197 for (uint32_t i = 0; i < mimeTypesNum; i++) {
198 napi_value mimeTypeNapi = nullptr;
199 NAPI_CALL(env, napi_get_element(env, mimeTypes, i, &mimeTypeNapi));
200
201 std::string mimeType;
202 bool ret = GetValue(env, mimeTypeNapi, mimeType);
203 if (!ret || (mimeType.size() > MIMETYPE_MAX_SIZE) || mimeType == "") {
204 return nullptr;
205 }
206 PASTEBOARD_HILOGD(PASTEBOARD_MODULE_CLIENT, "mimeType = %{public}s,", mimeType.c_str());
207
208 napi_value napiArrayBuffer = nullptr;
209 NAPI_CALL(env, napi_get_property(env, napiValue, mimeTypeNapi, &napiArrayBuffer));
210 void *data = nullptr;
211 size_t dataLen;
212 NAPI_CALL(env, napi_get_arraybuffer_info(env, napiArrayBuffer, &data, &dataLen));
213 customData->AddItemData(mimeType,
214 std::vector<uint8_t>(reinterpret_cast<uint8_t *>(data), reinterpret_cast<uint8_t *>(data) + dataLen));
215 }
216 return customData;
217 }
218
JSFillInstance(napi_env env,napi_value & instance)219 void PasteDataRecordNapi::JSFillInstance(napi_env env, napi_value &instance)
220 {
221 if (value_ == nullptr) {
222 return;
223 }
224 PASTEBOARD_HILOGI(PASTEBOARD_MODULE_JS_NAPI, "mimeType = %{public}s.", value_->GetMimeType().c_str());
225
226 auto mimeType = value_->GetMimeType();
227 SetNamedPropertyByStr(env, instance, "mimeType", mimeType.c_str());
228
229 auto plainText = value_->GetPlainText();
230 if (plainText != nullptr) {
231 SetNamedPropertyByStr(env, instance, "plainText", plainText->c_str());
232 PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "fill plainText.");
233 }
234
235 auto htmlText = value_->GetHtmlText();
236 if (htmlText != nullptr) {
237 SetNamedPropertyByStr(env, instance, "htmlText", htmlText->c_str());
238 PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "fill htmlText.");
239 }
240
241 auto uri = value_->GetUri();
242 if (uri != nullptr) {
243 SetNamedPropertyByStr(env, instance, "uri", uri->ToString().c_str());
244 PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "fill uri.");
245 }
246
247 auto want = value_->GetWant();
248 if (want != nullptr) {
249 napi_value jsWant = OHOS::AppExecFwk::WrapWant(env, *want);
250 napi_set_named_property(env, instance, "want", jsWant);
251 PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "fill want.");
252 }
253
254 auto pixelMap = value_->GetPixelMap();
255 if (pixelMap != nullptr) {
256 napi_value jsPixelMap = OHOS::Media::PixelMapNapi::CreatePixelMap(env, pixelMap);
257 napi_set_named_property(env, instance, "pixelMap", jsPixelMap);
258 PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "fill pixelMap.");
259 }
260
261 auto customData = value_->GetCustomData();
262 if (customData != nullptr) {
263 napi_value jsCustomData = PasteDataRecordNapi::SetNapiKvData(env, customData);
264 napi_set_named_property(env, instance, "data", jsCustomData);
265 PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "fill data.");
266 }
267 }
268
ConvertToText(napi_env env,napi_callback_info info)269 napi_value PasteDataRecordNapi::ConvertToText(napi_env env, napi_callback_info info)
270 {
271 PASTEBOARD_HILOGI(PASTEBOARD_MODULE_JS_NAPI, "ConvertToText is called!");
272
273 struct ExeContext {
274 std::string text;
275 PasteDataRecordNapi *obj = nullptr;
276 };
277 auto exeContext = std::make_shared<ExeContext>();
278 auto input = [exeContext](napi_env env, size_t argc, napi_value *argv, napi_value self) -> napi_status {
279 // convertToText(callback: AsyncCallback<string>) has 1 args
280 if (argc > 0
281 && !CheckArgsType(env, argv[0], napi_function, "Parameter error. The type of callback must be function.")) {
282 return napi_invalid_arg;
283 }
284 PasteDataRecordNapi *obj = nullptr;
285 napi_status status = napi_unwrap(env, self, reinterpret_cast<void **>(&obj));
286 if (status == napi_ok || obj != nullptr) {
287 exeContext->obj = obj;
288 }
289 return napi_ok;
290 };
291
292 auto exec = [exeContext](AsyncCall::Context *ctx) {
293 if ((exeContext->obj != nullptr) && (exeContext->obj->value_ != nullptr)) {
294 exeContext->text = exeContext->obj->value_->ConvertToText();
295 }
296 };
297 auto output = [exeContext](napi_env env, napi_value *result) -> napi_status {
298 napi_status status =
299 napi_create_string_utf8(env, (exeContext->text).c_str(), (exeContext->text).length(), result);
300 PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "napi_create_string_utf8 status = %{public}d", status);
301 return status;
302 };
303
304 // 0: the AsyncCall at the first position;
305 AsyncCall asyncCall(env, info, std::make_shared<AsyncCall::Context>(std::move(input), std::move(output)), 0);
306 return asyncCall.Call(env, exec);
307 }
308
ConvertToTextV9(napi_env env,napi_callback_info info)309 napi_value PasteDataRecordNapi::ConvertToTextV9(napi_env env, napi_callback_info info)
310 {
311 PASTEBOARD_HILOGI(PASTEBOARD_MODULE_JS_NAPI, "ConvertToTextV9 is called!");
312 return ConvertToText(env, info);
313 }
314
ToPlainText(napi_env env,napi_callback_info info)315 napi_value PasteDataRecordNapi::ToPlainText(napi_env env, napi_callback_info info)
316 {
317 PASTEBOARD_HILOGI(PASTEBOARD_MODULE_JS_NAPI, "ToPlainText is called!");
318 size_t argc = 1;
319 napi_value argv[1] = { 0 };
320 napi_value thisVar = nullptr;
321
322 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, NULL));
323 NAPI_ASSERT(env, argc >= ARGC_TYPE_SET0, "Wrong number of arguments");
324
325 PasteDataRecordNapi *obj = nullptr;
326 napi_status status = napi_unwrap(env, thisVar, reinterpret_cast<void **>(&obj));
327 if ((status != napi_ok) || (obj == nullptr)) {
328 PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "Get ToPlainText object failed");
329 return nullptr;
330 }
331
332 std::string str = obj->value_->ConvertToText();
333 napi_value result = nullptr;
334 napi_create_string_utf8(env, str.c_str(), NAPI_AUTO_LENGTH, &result);
335 return result;
336 }
337
PasteDataRecordInit(napi_env env,napi_value exports)338 napi_value PasteDataRecordNapi::PasteDataRecordInit(napi_env env, napi_value exports)
339 {
340 napi_property_descriptor properties[] = {
341 DECLARE_NAPI_FUNCTION("convertToText", ConvertToText),
342 DECLARE_NAPI_FUNCTION("convertToTextV9", ConvertToTextV9),
343 DECLARE_NAPI_FUNCTION("toPlainText", ToPlainText)
344 };
345
346 napi_status status = napi_ok;
347 napi_value constructor;
348 status = napi_define_class(env,
349 "PasteDataRecord",
350 NAPI_AUTO_LENGTH,
351 New,
352 nullptr,
353 sizeof(properties) / sizeof(napi_property_descriptor),
354 properties,
355 &constructor);
356 if (status != napi_ok) {
357 PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "Failed to define class at PasteDataRecordInit");
358 return nullptr;
359 }
360
361 status = napi_create_reference(env, constructor, 1, &g_pasteDataRecord);
362 if (status != napi_ok) {
363 PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "PasteDataRecordInit create reference failed");
364 return nullptr;
365 }
366 napi_set_named_property(env, exports, "PasteDataRecord", constructor);
367 return exports;
368 }
369
Destructor(napi_env env,void * nativeObject,void * finalize_hint)370 void PasteDataRecordNapi::Destructor(napi_env env, void *nativeObject, void *finalize_hint)
371 {
372 PasteDataRecordNapi *obj = static_cast<PasteDataRecordNapi *>(nativeObject);
373 delete obj;
374 }
375
New(napi_env env,napi_callback_info info)376 napi_value PasteDataRecordNapi::New(napi_env env, napi_callback_info info)
377 {
378 size_t argc = ARGC_TYPE_SET1;
379 napi_value argv[1] = {0};
380 napi_value thisVar = nullptr;
381 napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr);
382
383 // get native object
384 PasteDataRecordNapi *obj = new PasteDataRecordNapi();
385 obj->env_ = env;
386 NAPI_CALL(env, napi_wrap(env, thisVar, obj, PasteDataRecordNapi::Destructor, nullptr, &obj->wrapper_));
387 return thisVar;
388 }
389
NewInstance(napi_env env,napi_value & instance)390 napi_status PasteDataRecordNapi::NewInstance(napi_env env, napi_value &instance)
391 {
392 napi_status status = napi_invalid_arg;
393
394 napi_value constructor;
395 status = napi_get_reference_value(env, g_pasteDataRecord, &constructor);
396 if (status != napi_ok) {
397 PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "get reference failed");
398 return status;
399 }
400
401 status = napi_new_instance(env, constructor, 0, nullptr, &instance);
402 if (status != napi_ok) {
403 PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "new instance failed");
404 return status;
405 }
406
407 return napi_ok;
408 }
409 } // namespace MiscServicesNapi
410 } // namespace OHOS
411