1 /*
2 * Copyright (c) 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 #define LOG_TAG "UnifiedDataNapi"
16 #include "unified_data_napi.h"
17
18 #include "application_defined_record_napi.h"
19 #include "audio_napi.h"
20 #include "file_napi.h"
21 #include "folder_napi.h"
22 #include "html_napi.h"
23 #include "image_napi.h"
24 #include "link_napi.h"
25 #include "plain_text_napi.h"
26 #include "system_defined_appitem_napi.h"
27 #include "system_defined_form_napi.h"
28 #include "system_defined_pixelmap_napi.h"
29 #include "system_defined_record_napi.h"
30 #include "text_napi.h"
31 #include "unified_data.h"
32 #include "unified_record_napi.h"
33 #include "video_napi.h"
34
35 namespace OHOS {
36 namespace UDMF {
Constructor(napi_env env)37 napi_value UnifiedDataNapi::Constructor(napi_env env)
38 {
39 LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedDataNapi");
40 napi_property_descriptor properties[] = {
41 /* UnifiedData properties */
42 DECLARE_NAPI_FUNCTION("addRecord", AddRecord),
43 DECLARE_NAPI_FUNCTION("getRecords", GetRecords),
44 DECLARE_NAPI_FUNCTION("hasType", HasType),
45 DECLARE_NAPI_FUNCTION("getTypes", GetTypes),
46 DECLARE_NAPI_GETTER_SETTER("properties", GetProperties, SetProperties),
47 };
48 size_t count = sizeof(properties) / sizeof(properties[0]);
49 return NapiDataUtils::DefineClass(env, "UnifiedData", properties, count, UnifiedDataNapi::New);
50 }
51
New(napi_env env,napi_callback_info info)52 napi_value UnifiedDataNapi::New(napi_env env, napi_callback_info info)
53 {
54 LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedDataNapi");
55 UnifiedRecordNapi *uRecord = nullptr;
56 auto ctxt = std::make_shared<ContextBase>();
57 auto input = [env, info, ctxt, &uRecord](size_t argc, napi_value *argv) {
58 if (argc == 1) {
59 ctxt->status = napi_unwrap(env, *argv, reinterpret_cast<void **>(&uRecord));
60 ASSERT_BUSINESS_ERR(ctxt, (ctxt->status == napi_ok && uRecord != nullptr && uRecord->value_ != nullptr),
61 Status::E_INVALID_PARAMETERS, "Parameter error: parameter record type must be UnifiedRecord");
62 ctxt->status = UnifiedDataUtils::IsValidType(uRecord->value_->GetType()) ? napi_ok : napi_invalid_arg;
63 ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::E_ERROR, "invalid type!");
64 }
65 };
66
67 // Parsing input parameters
68 ctxt->GetCbInfoSync(env, info, input);
69 ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_ERROR, ctxt->error);
70 auto *uData = new (std::nothrow) UnifiedDataNapi();
71 ASSERT_ERR(ctxt->env, uData != nullptr, Status::E_ERROR, "no memory for unified data!");
72
73 // Create and bind UnifiedDataPropertiesNapi
74 int argc = 0;
75 napi_value argv[0] = {};
76 UnifiedDataPropertiesNapi* propertiesNapi = nullptr;
77 uData->propertyRef_ = NewWithRef(env, argc, argv, reinterpret_cast<void **>(&propertiesNapi),
78 UnifiedDataPropertiesNapi::Constructor(env));
79 if (propertiesNapi == nullptr) {
80 LOG_ERROR(UDMF_KITS_NAPI, "new UnifiedDataPropertiesNapi failed!");
81 if (uData->propertyRef_ != nullptr) {
82 napi_delete_reference(env, uData->propertyRef_);
83 }
84 delete(uData);
85 return nullptr;
86 }
87 uData->value_ = std::make_shared<UnifiedData>(propertiesNapi->value_);
88 if (uRecord) {
89 uData->value_->AddRecord(uRecord->value_);
90 }
91 auto status = napi_coerce_to_native_binding_object(
92 env, ctxt->self, DetachUnifiedData, AttachUnifiedData, uData, nullptr);
93 if (status != napi_ok) {
94 LOG_ERROR(UDMF_KITS_NAPI, "napi_coerce_to_native_binding_object failed!");
95 }
96 ASSERT_CALL(env, napi_wrap(env, ctxt->self, uData, Destructor, nullptr, nullptr), uData);
97 return ctxt->self;
98 }
99
AttachUnifiedData(napi_env env,void * value,void *)100 napi_value UnifiedDataNapi::AttachUnifiedData(napi_env env, void *value, void *)
101 {
102 if (value == nullptr) {
103 LOG_ERROR(UDMF_KITS_NAPI, "Invalid value.");
104 return nullptr;
105 }
106 auto *data = static_cast<UnifiedDataNapi *>(value);
107 napi_value jsData = nullptr;
108 auto status = napi_create_object(env, &jsData);
109 if (status != napi_ok) {
110 LOG_ERROR(UDMF_KITS_NAPI, "napi_create_object failed!");
111 delete data;
112 return nullptr;
113 }
114 napi_property_descriptor properties[] = {
115 DECLARE_NAPI_FUNCTION("addRecord", AddRecord),
116 DECLARE_NAPI_FUNCTION("getRecords", GetRecords),
117 DECLARE_NAPI_FUNCTION("hasType", HasType),
118 DECLARE_NAPI_FUNCTION("getTypes", GetTypes),
119 DECLARE_NAPI_GETTER_SETTER("properties", GetProperties, SetProperties),
120 };
121 status = napi_define_properties(env, jsData, sizeof(properties) / sizeof(properties[0]), properties);
122 if (status != napi_ok) {
123 LOG_ERROR(UDMF_KITS_NAPI, "napi_define_properties failed!");
124 delete data;
125 return nullptr;
126 }
127 status = napi_coerce_to_native_binding_object(
128 env, jsData, DetachUnifiedData, AttachUnifiedData, value, nullptr);
129 if (status != napi_ok) {
130 LOG_ERROR(UDMF_KITS_NAPI, "napi_coerce_to_native_binding_object failed!");
131 delete data;
132 return nullptr;
133 }
134 status = napi_wrap(env, jsData, value, Destructor, nullptr, nullptr);
135 if (status != napi_ok) {
136 LOG_ERROR(UDMF_KITS_NAPI, "napi_wrap failed!");
137 delete data;
138 return nullptr;
139 }
140 return jsData;
141 }
142
DetachUnifiedData(napi_env env,void * value,void *)143 void* UnifiedDataNapi::DetachUnifiedData(napi_env env, void *value, void *)
144 {
145 if (value == nullptr) {
146 LOG_ERROR(UDMF_KITS_NAPI, "Invalid value.");
147 return nullptr;
148 }
149 auto *origin = static_cast<UnifiedDataNapi *>(value);
150 auto result = new (std::nothrow) UnifiedDataNapi();
151 if (result == nullptr) {
152 LOG_ERROR(UDMF_KITS_NAPI, "Memory allocation failed.");
153 return nullptr;
154 }
155 result->value_ = origin->value_;
156
157 int argc = 0;
158 napi_value argv[0] = {};
159 UnifiedDataPropertiesNapi* propertiesNapi = nullptr;
160 result->propertyRef_ = NewWithRef(env, argc, argv, reinterpret_cast<void **>(&propertiesNapi),
161 UnifiedDataPropertiesNapi::Constructor(env));
162 if (propertiesNapi == nullptr) {
163 LOG_ERROR(UDMF_KITS_NAPI, "new UnifiedDataPropertiesNapi failed!");
164 if (result->propertyRef_ != nullptr) {
165 napi_delete_reference(env, result->propertyRef_);
166 }
167 delete result;
168 return nullptr;
169 }
170 propertiesNapi->value_ = origin->value_->GetProperties();
171 return result;
172 }
173
Destructor(napi_env env,void * data,void * hint)174 void UnifiedDataNapi::Destructor(napi_env env, void *data, void *hint)
175 {
176 LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedDataNapi finalize.");
177 auto *uData = static_cast<UnifiedDataNapi *>(data);
178 ASSERT_VOID(uData != nullptr, "finalize null!");
179 if (uData->propertyRef_ != nullptr) {
180 napi_delete_reference(env, uData->propertyRef_);
181 }
182 delete uData;
183 }
184
NewInstance(napi_env env,std::shared_ptr<UnifiedData> in,napi_value & out)185 napi_status UnifiedDataNapi::NewInstance(napi_env env, std::shared_ptr<UnifiedData> in, napi_value &out)
186 {
187 LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedDataNapi");
188 ASSERT_CALL_STATUS(env, napi_new_instance(env, Constructor(env), 0, nullptr, &out));
189
190 UnifiedDataNapi* unifiedData = nullptr;
191 napi_status status = napi_unwrap(env, out, reinterpret_cast<void **>(&unifiedData));
192 if (status != napi_ok || unifiedData == nullptr) {
193 LOG_ERROR(UDMF_KITS_NAPI, "napi_unwrap unifiedData failed, status=%{public}d", status);
194 return status;
195 }
196 unifiedData->value_ = in;
197
198 napi_value value;
199 status = napi_get_reference_value(env, unifiedData->propertyRef_, &value);
200 if (status != napi_ok) {
201 LOG_ERROR(UDMF_KITS_NAPI, "napi_get_reference_value propertyRef failed, status=%{public}d", status);
202 return status;
203 }
204 UnifiedDataPropertiesNapi* propertiesNapi = nullptr;
205 status = napi_unwrap(env, value, reinterpret_cast<void **>(&propertiesNapi));
206 if (status != napi_ok || propertiesNapi == nullptr) {
207 LOG_ERROR(UDMF_KITS_NAPI, "napi_unwrap propertiesNapi failed, status=%{public}d", status);
208 return status;
209 }
210 propertiesNapi->value_ = in->GetProperties();
211 return napi_ok;
212 }
213
GetUnifiedData(napi_env env,napi_callback_info info)214 UnifiedDataNapi *UnifiedDataNapi::GetUnifiedData(napi_env env, napi_callback_info info)
215 {
216 LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedDataNapi");
217 auto ctxt = std::make_shared<ContextBase>();
218 ctxt->GetCbInfoSync(env, info);
219 ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_ERROR, ctxt->error);
220 return static_cast<UnifiedDataNapi *>(ctxt->native);
221 }
222
AddRecord(napi_env env,napi_callback_info info)223 napi_value UnifiedDataNapi::AddRecord(napi_env env, napi_callback_info info)
224 {
225 LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedDataNapi");
226 UnifiedRecordNapi *uRecord = nullptr;
227 auto ctxt = std::make_shared<ContextBase>();
228 auto input = [env, info, ctxt, &uRecord](size_t argc, napi_value *argv) {
229 ASSERT_BUSINESS_ERR(ctxt, argc >= 1,
230 Status::E_INVALID_PARAMETERS, "Parameter error: Mandatory parameters are left unspecified");
231 ctxt->status = napi_unwrap(env, *argv, reinterpret_cast<void **>(&uRecord));
232 ASSERT_BUSINESS_ERR(ctxt, (ctxt->status == napi_ok && uRecord != nullptr && uRecord->value_ != nullptr),
233 Status::E_INVALID_PARAMETERS, "Parameter error: parameter record type must be UnifiedRecord");
234 ctxt->status = UnifiedDataUtils::IsValidType(uRecord->value_->GetType()) ? napi_ok : napi_invalid_arg;
235 ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::E_ERROR, "invalid type!");
236 };
237 ctxt->GetCbInfoSync(env, info, input);
238 ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_ERROR, ctxt->error);
239 auto *uData = static_cast<UnifiedDataNapi *>(ctxt->native);
240 ASSERT_ERR(
241 ctxt->env, (uData != nullptr && uData->value_ != nullptr), Status::E_ERROR, "invalid object!");
242 uData->value_->AddRecord(uRecord->value_);
243 return nullptr;
244 }
245
GetRecords(napi_env env,napi_callback_info info)246 napi_value UnifiedDataNapi::GetRecords(napi_env env, napi_callback_info info)
247 {
248 LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedDataNapi");
249 auto ctxt = std::make_shared<ContextBase>();
250 auto uData = GetUnifiedData(env, info);
251 ASSERT_ERR(
252 ctxt->env, (uData != nullptr && uData->value_ != nullptr), Status::E_ERROR, "invalid object!");
253 std::vector<std::shared_ptr<UnifiedRecord>> records = uData->value_->GetRecords();
254 napi_status status = napi_create_array_with_length(env, records.size(), &ctxt->output);
255 ASSERT_ERR(ctxt->env, status == napi_ok, Status::E_ERROR, "init array failed!");
256 int index = 0;
257 for (const std::shared_ptr<UnifiedRecord> &recordPtr : records) {
258 napi_value recordNapi = nullptr;
259 GetRecord(env, recordPtr, recordNapi);
260 ctxt->status = napi_set_element(env, ctxt->output, index++, recordNapi);
261 ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_ERROR, "set element failed!");
262 }
263 return ctxt->output;
264 }
265
GetRecord(napi_env env,std::shared_ptr<UnifiedRecord> in,napi_value & out)266 void UnifiedDataNapi::GetRecord(napi_env env, std::shared_ptr<UnifiedRecord> in, napi_value &out)
267 {
268 switch (in->GetType()) {
269 case TEXT: {
270 TextNapi::NewInstance(env, in, out);
271 break;
272 }
273 case PLAIN_TEXT: {
274 PlainTextNapi::NewInstance(env, in, out);
275 break;
276 }
277 case HTML: {
278 HtmlNapi::NewInstance(env, in, out);
279 break;
280 }
281 case HYPERLINK: {
282 LinkNapi::NewInstance(env, in, out);
283 break;
284 }
285 case FILE: {
286 FileNapi::NewInstance(env, in, out);
287 break;
288 }
289 case IMAGE: {
290 ImageNapi::NewInstance(env, in, out);
291 break;
292 }
293 case VIDEO: {
294 VideoNapi::NewInstance(env, in, out);
295 break;
296 }
297 case AUDIO: {
298 AudioNapi::NewInstance(env, in, out);
299 break;
300 }
301 case FOLDER: {
302 FolderNapi::NewInstance(env, in, out);
303 break;
304 }
305 case SYSTEM_DEFINED_RECORD: {
306 SystemDefinedRecordNapi::NewInstance(env, in, out);
307 break;
308 }
309 case SYSTEM_DEFINED_APP_ITEM: {
310 SystemDefinedAppItemNapi::NewInstance(env, in, out);
311 break;
312 }
313 case SYSTEM_DEFINED_FORM: {
314 SystemDefinedFormNapi::NewInstance(env, in, out);
315 break;
316 }
317 case SYSTEM_DEFINED_PIXEL_MAP: {
318 auto value = in->GetValue();
319 if (std::get_if<std::shared_ptr<OHOS::Media::PixelMap>>(&value)) {
320 UnifiedRecordNapi::NewInstance(env, in, out);
321 } else {
322 SystemDefinedPixelMapNapi::NewInstance(env, in, out);
323 }
324 break;
325 }
326 case APPLICATION_DEFINED_RECORD: {
327 ApplicationDefinedRecordNapi::NewInstance(env, in, out);
328 break;
329 }
330 default:
331 UnifiedRecordNapi::NewInstance(env, in, out);
332 LOG_INFO(UDMF_KITS_NAPI, "GetRecord default");
333 break;
334 }
335 }
336
HasType(napi_env env,napi_callback_info info)337 napi_value UnifiedDataNapi::HasType(napi_env env, napi_callback_info info)
338 {
339 LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedDataNapi");
340 std::string type;
341 auto ctxt = std::make_shared<ContextBase>();
342 auto input = [env, info, ctxt, &type](size_t argc, napi_value *argv) {
343 ASSERT_BUSINESS_ERR(ctxt, argc >= 1,
344 Status::E_INVALID_PARAMETERS, "Parameter error: Mandatory parameters are left unspecified");
345 ctxt->status = NapiDataUtils::GetValue(env, argv[0], type);
346 ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok,
347 Status::E_INVALID_PARAMETERS, "Parameter error: parameter type type must be string");
348 };
349 ctxt->GetCbInfoSync(env, info, input);
350 ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_ERROR, ctxt->error);
351 auto *uData = static_cast<UnifiedDataNapi *>(ctxt->native);
352 ASSERT_ERR(
353 ctxt->env, (uData != nullptr && uData->value_ != nullptr), Status::E_ERROR, "invalid object!");
354 bool ret = uData->value_->HasHigherFileType(type);
355 napi_value result = nullptr;
356 napi_get_boolean(env, ret, &result);
357 return result;
358 }
359
GetTypes(napi_env env,napi_callback_info info)360 napi_value UnifiedDataNapi::GetTypes(napi_env env, napi_callback_info info)
361 {
362 LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedDataNapi");
363 auto uData = GetUnifiedData(env, info);
364 ASSERT_ERR(env, (uData != nullptr && uData->value_ != nullptr), Status::E_ERROR, "invalid object!");
365
366 std::vector<std::string> Types = uData->value_->GetTypesLabels();
367 napi_value nTypes = nullptr;
368 napi_status status = napi_create_array(env, &nTypes);
369 ASSERT_ERR(env, status == napi_ok, Status::E_ERROR, "create array fail!");
370
371 size_t index = 0;
372 napi_value value = nullptr;
373 for (auto type : Types) {
374 napi_create_string_utf8(env, type.c_str(), NAPI_AUTO_LENGTH, &value);
375 napi_set_element(env, nTypes, index, value);
376 index++;
377 }
378 return nTypes;
379 }
380
GetProperties(napi_env env,napi_callback_info info)381 napi_value UnifiedDataNapi::GetProperties(napi_env env, napi_callback_info info)
382 {
383 LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedDataNapi");
384 napi_value value;
385 auto uData = GetUnifiedData(env, info);
386 ASSERT_ERR(env, (uData != nullptr && uData->value_ != nullptr), Status::E_ERROR, "invalid object!");
387 ASSERT_ERR(env, (uData != nullptr && uData->propertyRef_ != nullptr), Status::E_ERROR, "invalid properties!");
388 NAPI_CALL(env, napi_get_reference_value(env, uData->propertyRef_, &value));
389 return value;
390 }
391
GetPropertiesNapi(napi_env env)392 UnifiedDataPropertiesNapi* UnifiedDataNapi::GetPropertiesNapi(napi_env env)
393 {
394 napi_value value;
395 NAPI_CALL(env, napi_get_reference_value(env, propertyRef_, &value));
396 UnifiedDataPropertiesNapi* out = nullptr;
397 napi_status status = napi_unwrap(env, value, reinterpret_cast<void**>(&out));
398 ASSERT_ERR(env, status == napi_ok && out != nullptr, Status::E_ERROR, "napi_unwrap failed");
399 return out;
400 }
401
SetProperties(napi_env env,napi_callback_info info)402 napi_value UnifiedDataNapi::SetProperties(napi_env env, napi_callback_info info)
403 {
404 LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedDataNapi");
405 auto ctxt = std::make_shared<ContextBase>();
406 auto input = [env, ctxt](size_t argc, napi_value* argv) {
407 ASSERT_BUSINESS_ERR(ctxt, argc >= 1,
408 Status::E_INVALID_PARAMETERS, "Parameter error: Mandatory parameters are left unspecified");
409 UnifiedDataPropertiesNapi* propertiesNapi = nullptr;
410 ctxt->status = Unwrap(env, argv[0], reinterpret_cast<void**>(&propertiesNapi),
411 UnifiedDataPropertiesNapi::Constructor(env));
412 ASSERT_BUSINESS_ERR(ctxt, propertiesNapi != nullptr,
413 Status::E_INVALID_PARAMETERS, "Parameter error: parameter properties type must be UnifiedDataProperties");
414
415 auto uData = static_cast<UnifiedDataNapi*>(ctxt->native);
416 if (uData->propertyRef_ != nullptr) {
417 napi_delete_reference(env, uData->propertyRef_);
418 }
419 ctxt->status = napi_create_reference(env, argv[0], 1, &uData->propertyRef_);
420 ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok,
421 Status::E_ERROR, "napi_create_reference to properties failed!");
422 uData->value_->SetProperties(propertiesNapi->value_);
423 };
424 ctxt->GetCbInfoSync(env, info, input);
425 ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_ERROR, ctxt->error);
426 return ctxt->self;
427 }
428
NewWithRef(napi_env env,size_t argc,napi_value * argv,void ** out,napi_value constructor)429 napi_ref UnifiedDataNapi::NewWithRef(napi_env env, size_t argc, napi_value *argv, void **out, napi_value constructor)
430 {
431 napi_value object = nullptr;
432 napi_status status = napi_new_instance(env, constructor, argc, argv, &object);
433 ASSERT_ERR(env, status == napi_ok && object != nullptr, Status::E_ERROR, "napi_new_instance failed");
434
435 status = napi_unwrap(env, object, out);
436 ASSERT_ERR(env, status == napi_ok && out != nullptr, Status::E_ERROR, "napi_unwrap failed");
437
438 napi_ref ref = nullptr;
439 status = napi_create_reference(env, object, 1, &ref);
440 ASSERT_ERR(env, status == napi_ok && ref != nullptr, Status::E_ERROR, "napi_create_reference failed");
441 return ref;
442 }
443
Unwrap(napi_env env,napi_value in,void ** out,napi_value constructor)444 napi_status UnifiedDataNapi::Unwrap(napi_env env, napi_value in, void **out, napi_value constructor)
445 {
446 if (constructor != nullptr) {
447 bool isInstance = false;
448 napi_instanceof(env, in, constructor, &isInstance);
449 if (!isInstance) {
450 LOG_ERROR(UDMF_KITS_NAPI, "not a instance of *");
451 return napi_invalid_arg;
452 }
453 }
454 return napi_unwrap(env, in, out);
455 }
456 } // namespace UDMF
457 } // namespace OHOS