• 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 "napi_pasteboard_common.h"
16 #include "pasteboard_hilog.h"
17 
18 namespace OHOS {
19 namespace MiscServicesNapi {
20 using namespace OHOS::MiscServices;
21 const size_t ARGC_TYPE_SET2 = 2;
22 constexpr size_t STR_TAIL_LENGTH = 1;
23 constexpr int32_t MIMETYPE_MAX_SIZE = 1024;
24 
GetCallbackErrorValue(napi_env env,int32_t errorCode)25 napi_value GetCallbackErrorValue(napi_env env, int32_t errorCode)
26 {
27     napi_value result = nullptr;
28     napi_value eCode = nullptr;
29     NAPI_CALL(env, napi_create_int32(env, errorCode, &eCode));
30     NAPI_CALL(env, napi_create_object(env, &result));
31     NAPI_CALL(env, napi_set_named_property(env, result, "code", eCode));
32     return result;
33 }
34 
SetCallback(const napi_env & env,const napi_ref & callbackIn,const napi_value * results)35 void SetCallback(const napi_env &env, const napi_ref &callbackIn, const napi_value *results)
36 {
37     if (results == nullptr) {
38         return;
39     }
40     napi_value callback = nullptr;
41     napi_value resultOut = nullptr;
42     napi_get_reference_value(env, callbackIn, &callback);
43     napi_call_function(env, nullptr, callback, ARGC_TYPE_SET2, results, &resultOut);
44 }
45 
NapiGetNull(napi_env env)46 napi_value NapiGetNull(napi_env env)
47 {
48     napi_value result = nullptr;
49     napi_get_null(env, &result);
50     return result;
51 }
52 
CreateNapiNumber(napi_env env,int32_t num)53 napi_value CreateNapiNumber(napi_env env, int32_t num)
54 {
55     napi_value value = nullptr;
56     napi_create_int32(env, num, &value);
57     return value;
58 }
59 
CreateNapiString(napi_env env,std::string str)60 napi_value CreateNapiString(napi_env env, std::string str)
61 {
62     napi_value value = nullptr;
63     napi_create_string_utf8(env, str.c_str(), NAPI_AUTO_LENGTH, &value);
64     return value;
65 }
66 
67 /* napi_value <-> std::string */
GetValue(napi_env env,napi_value in,std::string & out)68 bool GetValue(napi_env env, napi_value in, std::string &out)
69 {
70     napi_valuetype type = napi_undefined;
71     NAPI_CALL_BASE(env, napi_typeof(env, in, &type), false);
72     NAPI_ASSERT_BASE(env, type == napi_string, "Wrong argument type. String expected.", false);
73 
74     size_t len = 0;
75     NAPI_CALL_BASE(env, napi_get_value_string_utf8(env, in, nullptr, 0, &len), false);
76     if (len < 0) {
77         return false;
78     }
79 
80     size_t length = 0;
81     out.resize(len + STR_TAIL_LENGTH, 0);
82     NAPI_CALL_BASE(env, napi_get_value_string_utf8(env, in, out.data(), len + STR_TAIL_LENGTH, &length), false);
83     out.resize(len);
84 
85     return true;
86 }
87 
88 /* napi_value <-> std::set<Pattern> */
GetValue(napi_env env,napi_value in,std::set<MiscServices::Pattern> & out)89 bool GetValue(napi_env env, napi_value in, std::set<MiscServices::Pattern> &out)
90 {
91     bool isArray = false;
92     NAPI_CALL_BASE(env, napi_is_array(env, in, &isArray), false);
93     if (!isArray) {
94         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "Wrong argument type. pattern/uint32 array expected.");
95         return false;
96     }
97 
98     uint32_t len = 0;
99     napi_status status = napi_get_array_length(env, in, &len);
100     if (status != napi_ok || len == 0) {
101         PASTEBOARD_HILOGE(
102             PASTEBOARD_MODULE_JS_NAPI, "napi_get_array_length status = %{public}d, len = %{public}d", status, len);
103         return false;
104     }
105 
106     for (uint32_t i = 0; i < len; i++) {
107         napi_value element;
108         status = napi_get_element(env, in, i, &element);
109         if (status != napi_ok) {
110             PASTEBOARD_HILOGE(
111                 PASTEBOARD_MODULE_JS_NAPI, "napi_get_element%{public}d err status = %{public}d", i, status);
112             return false;
113         }
114         uint32_t pattern;
115         status = napi_get_value_uint32(env, element, &pattern);
116         if (status != napi_ok) {
117             PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "napi_get_value_uint32 err status = %{public}d", status);
118             return false;
119         }
120         if (pattern >= static_cast<uint32_t>(Pattern::COUNT)) {
121             PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "Unsupported pattern value: %{public}d", pattern);
122             return false;
123         }
124         out.insert(static_cast<Pattern>(pattern));
125     }
126     return true;
127 }
128 
129 /* napi_value <-> std::set<Pattern> */
SetValue(napi_env env,std::set<Pattern> & in,napi_value & result)130 napi_status SetValue(napi_env env, std::set<Pattern> &in, napi_value &result)
131 {
132     napi_status status = napi_create_array_with_length(env, in.size(), &result);
133     if (status != napi_ok) {
134         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "napi_create_array_with_length error status = %{public}d", status);
135         return status;
136     }
137     int i = 0;
138     for (auto &pattern : in) {
139         napi_value element;
140         status = napi_create_uint32(env, static_cast<uint32_t>(pattern), &element);
141         if (status != napi_ok) {
142             PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "napi_create_uint32 error status = %{public}d", status);
143             return status;
144         }
145         status = napi_set_element(env, result, i, element);
146         if (status != napi_ok) {
147             PASTEBOARD_HILOGE(
148                 PASTEBOARD_MODULE_JS_NAPI, "napi_set_element %{public}d err status = %{public}d", i, status);
149             return status;
150         }
151         ++i;
152     }
153     return status;
154 }
155 
CheckArgsType(napi_env env,napi_value in,napi_valuetype expectedType,const char * message)156 bool CheckArgsType(napi_env env, napi_value in, napi_valuetype expectedType, const char *message)
157 {
158     napi_valuetype type = napi_undefined;
159     NAPI_CALL_BASE(env, napi_typeof(env, in, &type), false);
160     int32_t errCode = static_cast<int32_t>(JSErrorCode::INVALID_PARAMETERS);
161     if (type != expectedType) {
162         napi_throw_error(env, std::to_string(errCode).c_str(), message);
163         return false;
164     }
165     return true;
166 }
167 
CheckExpression(napi_env env,bool flag,MiscServices::JSErrorCode errCode,const char * message)168 bool CheckExpression(napi_env env, bool flag, MiscServices::JSErrorCode errCode, const char *message)
169 {
170     if (!flag) {
171         NAPI_CALL_BASE(
172             env, napi_throw_error(env, std::to_string(static_cast<int32_t>(errCode)).c_str(), message), false);
173         return false;
174     }
175     return true;
176 }
177 
178 // Check Parameters of CreateData, CreateRecord and AddRecord
CheckArgs(napi_env env,napi_value * argv,size_t argc,std::string & mimeType)179 bool CheckArgs(napi_env env, napi_value *argv, size_t argc, std::string &mimeType)
180 {
181     // 2: CreateRecord, CreateRecord and AddRecord has 2 args.
182     if (!CheckExpression(env, argc >= ARGC_TYPE_SET2, JSErrorCode::INVALID_PARAMETERS,
183         "Parameter error. The number of arguments cannot be less than two.")) {
184         return false;
185     }
186 
187     bool ret = CheckArgsMimeType(env, argv[0], mimeType);
188     if (!ret) {
189         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "GetValue failed");
190         return false;
191     }
192     if (!CheckExpression(
193         env, mimeType != "", JSErrorCode::INVALID_PARAMETERS, "Parameter error. mimeType cannot be empty.") ||
194         !CheckExpression(env, mimeType.size() <= MIMETYPE_MAX_SIZE, JSErrorCode::INVALID_PARAMETERS,
195             "Parameter error. The length of mimeType cannot be greater than 1024 bytes.")) {
196         return false;
197     }
198 
199     if (mimeType == MIMETYPE_TEXT_URI || mimeType == MIMETYPE_TEXT_PLAIN || mimeType == MIMETYPE_TEXT_HTML) {
200         if (!CheckArgsType(env, argv[1], napi_string, "Parameter error. The type of mimeType must be string.")) {
201             return false;
202         }
203     } else if (mimeType == MIMETYPE_PIXELMAP) {
204         if (!CheckExpression(env, Media::PixelMapNapi::GetPixelMap(env, argv[1]) != nullptr,
205                 JSErrorCode::INVALID_PARAMETERS, "Parameter error. Actual mimeType is not mimetype_pixelmap.")) {
206             return false;
207         }
208     } else if (mimeType == MIMETYPE_TEXT_WANT) {
209         AAFwk::Want want;
210         ret = OHOS::AppExecFwk::UnwrapWant(env, argv[1], want);
211         if (!CheckExpression(env, ret, JSErrorCode::INVALID_PARAMETERS,
212             "Parameter error. Actual mimeType is not mimetype_text_want.")) {
213             return false;
214         }
215     } else {
216         bool isArrayBuffer = false;
217         NAPI_CALL_BASE(env, napi_is_arraybuffer(env, argv[1], &isArrayBuffer), false);
218         if (!CheckExpression(env, isArrayBuffer, JSErrorCode::INVALID_PARAMETERS,
219             "Parameter error. The mimeType is not an arraybuffer.")) {
220             return false;
221         }
222     }
223     return true;
224 }
225 
CheckArgsMimeType(napi_env env,napi_value in,std::string & mimeType)226 bool CheckArgsMimeType(napi_env env, napi_value in, std::string &mimeType)
227 {
228     bool ret = CheckArgsType(env, in, napi_string, "Parameter error. The type of mimeType must be string.");
229     if (!ret) {
230         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "Wrong argument type. String expected.");
231         return false;
232     }
233     ret = GetValue(env, in, mimeType);
234     if (!ret) {
235         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "GetValue failed");
236         return false;
237     }
238     if (!CheckExpression(
239         env, mimeType != "", JSErrorCode::INVALID_PARAMETERS, "Parameter error. mimeType cannot be empty.") ||
240         !CheckExpression(env, mimeType.size() <= MIMETYPE_MAX_SIZE, JSErrorCode::INVALID_PARAMETERS,
241         "Parameter error. The length of mimeType cannot be greater than 1024 bytes.")) {
242         return false;
243     }
244     return true;
245 }
246 
CheckArgsArray(napi_env env,napi_value in,std::vector<std::string> & mimeTypes)247 bool CheckArgsArray(napi_env env, napi_value in, std::vector<std::string> &mimeTypes)
248 {
249     napi_valuetype type = napi_undefined;
250     NAPI_CALL_BASE(env, napi_typeof(env, in, &type), false);
251     int32_t errCode = static_cast<int32_t>(JSErrorCode::INVALID_PARAMETERS);
252     if (type != napi_object) {
253         napi_throw_error(env, std::to_string(errCode).c_str(), "Wrong argument type. Object expected.");
254         return false;
255     }
256 
257     bool isArray = false;
258     NAPI_CALL_BASE(env, napi_is_array(env, in, &isArray), false);
259     if (!isArray) {
260         return false;
261     }
262 
263     uint32_t length = 0;
264     NAPI_CALL_BASE(env, napi_get_array_length(env, in, &length), false);
265     napi_value element;
266     for (uint32_t i = 0; i < length; i++) {
267         NAPI_CALL_BASE(env, napi_get_element(env, in, i, &element), false);
268         std::string mimeType;
269         if (!GetValue(env, element, mimeType)) {
270             return false;
271         }
272         mimeTypes.emplace_back(mimeType);
273     }
274 
275     return true;
276 }
277 
CheckArgsFunc(napi_env env,napi_value in,napi_ref & provider)278 bool CheckArgsFunc(napi_env env, napi_value in, napi_ref &provider)
279 {
280     napi_valuetype type = napi_undefined;
281     NAPI_CALL_BASE(env, napi_typeof(env, in, &type), false);
282     int32_t errCode = static_cast<int32_t>(JSErrorCode::INVALID_PARAMETERS);
283     if (type != napi_function) {
284         napi_throw_error(env, std::to_string(errCode).c_str(), "Wrong argument type. function expected.");
285         return false;
286     }
287 
288     NAPI_CALL_BASE(env, napi_create_reference(env, in, 1, &provider), false);
289 
290     return true;
291 }
292 
CheckArgsVector(napi_env env,napi_value in,std::shared_ptr<std::vector<std::pair<std::string,std::shared_ptr<EntryValue>>>> result)293 bool CheckArgsVector(napi_env env, napi_value in,
294     std::shared_ptr<std::vector<std::pair<std::string, std::shared_ptr<EntryValue>>>> result)
295 {
296     napi_valuetype valueType = napi_undefined;
297     NAPI_CALL_BASE(env, napi_typeof(env, in, &valueType), false);
298     if (!CheckExpression(env, valueType == napi_object, JSErrorCode::INVALID_PARAMETERS,
299         "Parameter error. When there is only one parameter, it must be a Record.")) {
300         return false;
301     }
302 
303     napi_value typeValueMap = nullptr;
304     NAPI_CALL_BASE(env, napi_get_property_names(env, in, &typeValueMap), false);
305     uint32_t length = 0;
306     NAPI_CALL_BASE(env, napi_get_array_length(env, typeValueMap, &length), false);
307 
308     PASTEBOARD_HILOGD(PASTEBOARD_MODULE_JS_NAPI, "length = %{public}u", length);
309     for (uint32_t i = 0; i < length; i++) {
310         napi_value mimeTypeNapi = nullptr;
311         NAPI_CALL_BASE(env, napi_get_element(env, typeValueMap, i, &mimeTypeNapi), false);
312         std::string mimeType;
313         bool ret = CheckArgsMimeType(env, mimeTypeNapi, mimeType);
314         if (!ret) {
315             return false;
316         }
317         napi_value value = nullptr;
318         std::shared_ptr<EntryValue> entryValue = std::make_shared<EntryValue>();
319         NAPI_CALL_BASE(env, napi_get_property(env, in, mimeTypeNapi, &value), false);
320         if (!GetNativeValue(env, mimeType, value, *entryValue)) {
321             PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "GetNativeValue failed");
322             return false;
323         }
324         result->emplace_back(std::make_pair(mimeType, entryValue));
325     }
326     return true;
327 }
328 
CheckRetCode(napi_env env,int32_t retCode,const std::vector<JSErrorCode> & focusErrCodes)329 bool CheckRetCode(napi_env env, int32_t retCode, const std::vector<JSErrorCode> &focusErrCodes)
330 {
331     auto errInfo = NapiDataUtils::GetErrInfo(static_cast<PasteboardError>(retCode));
332     auto iter = std::find(focusErrCodes.begin(), focusErrCodes.end(), errInfo.first);
333     if (iter != focusErrCodes.end()) {
334         NAPI_CALL_BASE(env,
335             napi_throw_error(env, std::to_string(static_cast<int32_t>(errInfo.first)).c_str(), errInfo.second.c_str()),
336             false);
337         return false;
338     }
339     return true;
340 }
341 
GetContextSetErr(const std::shared_ptr<GetContextInfo> context,int32_t retCode,const std::vector<JSErrorCode> & focusErrCodes,std::string defaultMsg)342 bool GetContextSetErr(const std::shared_ptr<GetContextInfo> context, int32_t retCode,
343     const std::vector<JSErrorCode> &focusErrCodes, std::string defaultMsg)
344 {
345     auto errInfo = NapiDataUtils::GetErrInfo(static_cast<PasteboardError>(retCode));
346     auto iter = std::find(focusErrCodes.begin(), focusErrCodes.end(), errInfo.first);
347     if (iter != focusErrCodes.end()) {
348         errInfo.second = defaultMsg.empty() ? errInfo.second : defaultMsg;
349         context->SetErrInfo(static_cast<int32_t>(errInfo.first), errInfo.second);
350         context->status = napi_generic_failure;
351         return true;
352     }
353     return false;
354 }
355 
UnifiedContextSetErr(const std::shared_ptr<GetUnifiedContextInfo> context,int32_t retCode,const std::vector<JSErrorCode> & focusErrCodes,std::string defaultMsg)356 bool UnifiedContextSetErr(const std::shared_ptr<GetUnifiedContextInfo> context, int32_t retCode,
357     const std::vector<JSErrorCode> &focusErrCodes, std::string defaultMsg)
358 {
359     auto errInfo = NapiDataUtils::GetErrInfo(static_cast<PasteboardError>(retCode));
360     auto iter = std::find(focusErrCodes.begin(), focusErrCodes.end(), errInfo.first);
361     if (iter != focusErrCodes.end()) {
362         errInfo.second = defaultMsg.empty() ? errInfo.second : defaultMsg;
363         context->SetErrInfo(static_cast<int32_t>(errInfo.first), errInfo.second);
364         context->status = napi_generic_failure;
365         return true;
366     }
367     return false;
368 }
369 
ConvertEntryValue(napi_env env,napi_value * result,std::string & mimeType,std::shared_ptr<PasteDataEntry> value)370 napi_status ConvertEntryValue(napi_env env, napi_value *result, std::string &mimeType,
371     std::shared_ptr<PasteDataEntry> value)
372 {
373     if (value == nullptr) {
374         PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "failed to find dataEntry");
375         return napi_generic_failure;
376     }
377     if (mimeType == MIMETYPE_TEXT_URI) {
378         std::shared_ptr<Uri> uri = value->ConvertToUri();
379         if (uri == nullptr) {
380             return napi_generic_failure;
381         }
382         std::string str = uri->ToString();
383         return napi_create_string_utf8(env, str.c_str(), str.size(), result);
384     } else if (mimeType == MIMETYPE_TEXT_PLAIN) {
385         std::shared_ptr<std::string> str = value->ConvertToPlainText();
386         if (str == nullptr) {
387             return napi_generic_failure;
388         }
389         return napi_create_string_utf8(env, str->c_str(), str->size(), result);
390     } else if (mimeType == MIMETYPE_TEXT_HTML) {
391         std::shared_ptr<std::string> str = value->ConvertToHtml();
392         if (str == nullptr) {
393             return napi_generic_failure;
394         }
395         return napi_create_string_utf8(env, str->c_str(), str->size(), result);
396     } else if (mimeType == MIMETYPE_PIXELMAP) {
397         std::shared_ptr<Media::PixelMap> pixelMap = value->ConvertToPixelMap();
398         if (!CheckExpression(env, pixelMap != nullptr,
399             JSErrorCode::INVALID_PARAMETERS, "Parameter error. pixelMap get failed")) {
400             return napi_generic_failure;
401         }
402         *result = Media::PixelMapNapi::CreatePixelMap(env, pixelMap);
403         return napi_ok;
404     } else if (mimeType == MIMETYPE_TEXT_WANT) {
405         std::shared_ptr<AAFwk::Want> want = value->ConvertToWant();
406         if (!CheckExpression(env, want != nullptr,
407             JSErrorCode::INVALID_PARAMETERS, "Parameter error. want get failed")) {
408             return napi_generic_failure;
409         }
410         *result = AppExecFwk::WrapWant(env, *want);
411         return napi_ok;
412     } else {
413         std::shared_ptr<MineCustomData> customData = value->ConvertToCustomData();
414         if (customData == nullptr) {
415             return napi_generic_failure;
416         }
417         auto itemData = customData->GetItemData();
418         auto item = itemData.find(mimeType);
419         if (item == itemData.end()) {
420             return napi_generic_failure;
421         }
422         std::vector<uint8_t> dataArray = item->second;
423         void *data = nullptr;
424         size_t len = dataArray.size();
425         NAPI_CALL_BASE(env, napi_create_arraybuffer(env, len, &data, result), napi_generic_failure);
426         if (memcpy_s(data, len, reinterpret_cast<const void *>(dataArray.data()), len) != 0) {
427             PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "memcpy_s failed");
428             return napi_generic_failure;
429         }
430         return napi_ok;
431     }
432 }
433 
GetNativeValue(napi_env env,const std::string & type,napi_value valueNapi,EntryValue & value)434 bool GetNativeValue(napi_env env, const std::string &type, napi_value valueNapi, EntryValue &value)
435 {
436     bool isArrayBuffer = false;
437     NAPI_CALL_BASE(env, napi_is_arraybuffer(env, valueNapi, &isArrayBuffer), false);
438     if (isArrayBuffer) {
439         void *data = nullptr;
440         size_t dataLen = 0;
441         NAPI_CALL_BASE(env, napi_get_arraybuffer_info(env, valueNapi, &data, &dataLen), false);
442         value = std::vector<uint8_t>(reinterpret_cast<uint8_t *>(data), reinterpret_cast<uint8_t *>(data) + dataLen);
443         return true;
444     }
445 
446     napi_status status;
447     napi_valuetype valueType = napi_undefined;
448     status = napi_typeof(env, valueNapi, &valueType);
449     NAPI_ASSERT_BASE(env, status == napi_ok,
450         "Parameter error: parameter value type must be ValueType", false);
451     if (valueType == napi_object) {
452         if (type == MIMETYPE_PIXELMAP) {
453             value = std::shared_ptr<OHOS::Media::PixelMap>(nullptr);
454         } else if (type == MIMETYPE_TEXT_WANT) {
455             value = std::shared_ptr<OHOS::AAFwk::Want>(nullptr);
456         } else {
457             PASTEBOARD_HILOGE(PASTEBOARD_MODULE_JS_NAPI, "Parameter error: error ValueType");
458             value = nullptr;
459         }
460     } else if (valueType == napi_string) {
461         value = std::string();
462     } else if (valueType == napi_number) {
463         value = double();
464     } else if (valueType == napi_boolean) {
465         value = bool();
466     } else if (valueType == napi_undefined) {
467         value = std::monostate();
468     } else if (valueType == napi_null) {
469         value = nullptr;
470     }
471     std::visit([&](auto &value) { status = NapiDataUtils::GetValue(env, valueNapi, value); }, value);
472     NAPI_ASSERT_BASE(env, status == napi_ok, "get unifiedRecord failed", false);
473     return true;
474 }
475 } // namespace MiscServicesNapi
476 } // namespace OHOS