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     uData->value_ = std::make_shared<UnifiedData>(propertiesNapi->value_);
80     if (uRecord) {
81         uData->value_->AddRecord(uRecord->value_);
82     }
83     ASSERT_CALL(env, napi_wrap(env, ctxt->self, uData, Destructor, nullptr, nullptr), uData);
84     return ctxt->self;
85 }
86 
Destructor(napi_env env,void * data,void * hint)87 void UnifiedDataNapi::Destructor(napi_env env, void *data, void *hint)
88 {
89     LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedDataNapi finalize.");
90     auto *uData = static_cast<UnifiedDataNapi *>(data);
91     ASSERT_VOID(uData != nullptr, "finalize null!");
92     if (uData->propertyRef_ != nullptr) {
93         napi_delete_reference(env, uData->propertyRef_);
94     }
95     delete uData;
96 }
97 
NewInstance(napi_env env,std::shared_ptr<UnifiedData> in,napi_value & out)98 napi_status UnifiedDataNapi::NewInstance(napi_env env, std::shared_ptr<UnifiedData> in, napi_value &out)
99 {
100     LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedDataNapi");
101     ASSERT_CALL_STATUS(env, napi_new_instance(env, Constructor(env), 0, nullptr, &out));
102     auto *unifiedData = new (std::nothrow) UnifiedDataNapi();
103     ASSERT_ERR_STATUS(env, unifiedData != nullptr, Status::E_ERROR, "no memory for unified data!");
104     unifiedData->value_ = in;
105     ASSERT_CALL_DELETE_STATUS(env, napi_wrap(env, out, unifiedData, Destructor, nullptr, nullptr), unifiedData);
106     return napi_ok;
107 }
108 
GetUnifiedData(napi_env env,napi_callback_info info)109 UnifiedDataNapi *UnifiedDataNapi::GetUnifiedData(napi_env env, napi_callback_info info)
110 {
111     LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedDataNapi");
112     auto ctxt = std::make_shared<ContextBase>();
113     ctxt->GetCbInfoSync(env, info);
114     ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_ERROR, ctxt->error);
115     return static_cast<UnifiedDataNapi *>(ctxt->native);
116 }
117 
AddRecord(napi_env env,napi_callback_info info)118 napi_value UnifiedDataNapi::AddRecord(napi_env env, napi_callback_info info)
119 {
120     LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedDataNapi");
121     UnifiedRecordNapi *uRecord = nullptr;
122     auto ctxt = std::make_shared<ContextBase>();
123     auto input = [env, info, ctxt, &uRecord](size_t argc, napi_value *argv) {
124         ASSERT_BUSINESS_ERR(ctxt, argc >= 1,
125             Status::E_INVALID_PARAMETERS, "Parameter error: Mandatory parameters are left unspecified");
126         ctxt->status = napi_unwrap(env, *argv, reinterpret_cast<void **>(&uRecord));
127         ASSERT_BUSINESS_ERR(ctxt, (ctxt->status == napi_ok && uRecord != nullptr && uRecord->value_ != nullptr),
128             Status::E_INVALID_PARAMETERS, "Parameter error: parameter record type must be UnifiedRecord");
129         ctxt->status = UnifiedDataUtils::IsValidType(uRecord->value_->GetType()) ? napi_ok : napi_invalid_arg;
130         ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok, Status::E_ERROR, "invalid type!");
131     };
132     ctxt->GetCbInfoSync(env, info, input);
133     ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_ERROR, ctxt->error);
134     auto *uData = static_cast<UnifiedDataNapi *>(ctxt->native);
135     ASSERT_ERR(
136         ctxt->env, (uData != nullptr && uData->value_ != nullptr), Status::E_ERROR, "invalid object!");
137     uData->value_->AddRecord(uRecord->value_);
138     return nullptr;
139 }
140 
GetRecords(napi_env env,napi_callback_info info)141 napi_value UnifiedDataNapi::GetRecords(napi_env env, napi_callback_info info)
142 {
143     LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedDataNapi");
144     auto ctxt = std::make_shared<ContextBase>();
145     auto uData = GetUnifiedData(env, info);
146     ASSERT_ERR(
147         ctxt->env, (uData != nullptr && uData->value_ != nullptr), Status::E_ERROR, "invalid object!");
148     std::vector<std::shared_ptr<UnifiedRecord>> records = uData->value_->GetRecords();
149     napi_status status = napi_create_array_with_length(env, records.size(), &ctxt->output);
150     ASSERT_ERR(ctxt->env, status == napi_ok, Status::E_ERROR, "init array failed!");
151     int index = 0;
152     for (const std::shared_ptr<UnifiedRecord> &recordPtr : records) {
153         napi_value recordNapi = nullptr;
154         GetRecord(env, recordPtr, recordNapi);
155         ctxt->status = napi_set_element(env, ctxt->output, index++, recordNapi);
156         ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_ERROR, "set element failed!");
157     }
158     return ctxt->output;
159 }
160 
GetRecord(napi_env env,std::shared_ptr<UnifiedRecord> in,napi_value & out)161 void UnifiedDataNapi::GetRecord(napi_env env, std::shared_ptr<UnifiedRecord> in, napi_value &out)
162 {
163     switch (in->GetType()) {
164         case TEXT: {
165             TextNapi::NewInstance(env, in, out);
166             break;
167         }
168         case PLAIN_TEXT: {
169             PlainTextNapi::NewInstance(env, in, out);
170             break;
171         }
172         case HTML: {
173             HtmlNapi::NewInstance(env, in, out);
174             break;
175         }
176         case HYPERLINK: {
177             LinkNapi::NewInstance(env, in, out);
178             break;
179         }
180         case FILE: {
181             FileNapi::NewInstance(env, in, out);
182             break;
183         }
184         case IMAGE: {
185             ImageNapi::NewInstance(env, in, out);
186             break;
187         }
188         case VIDEO: {
189             VideoNapi::NewInstance(env, in, out);
190             break;
191         }
192         case AUDIO: {
193             AudioNapi::NewInstance(env, in, out);
194             break;
195         }
196         case FOLDER: {
197             FolderNapi::NewInstance(env, in, out);
198             break;
199         }
200         case SYSTEM_DEFINED_RECORD: {
201             SystemDefinedRecordNapi::NewInstance(env, in, out);
202             break;
203         }
204         case SYSTEM_DEFINED_APP_ITEM: {
205             SystemDefinedAppItemNapi::NewInstance(env, in, out);
206             break;
207         }
208         case SYSTEM_DEFINED_FORM: {
209             SystemDefinedFormNapi::NewInstance(env, in, out);
210             break;
211         }
212         case SYSTEM_DEFINED_PIXEL_MAP: {
213             auto value = in->GetValue();
214             if (std::get_if<std::shared_ptr<OHOS::Media::PixelMap>>(&value)) {
215                 UnifiedRecordNapi::NewInstance(env, in, out);
216             } else {
217                 SystemDefinedPixelMapNapi::NewInstance(env, in, out);
218             }
219             break;
220         }
221         case APPLICATION_DEFINED_RECORD: {
222             ApplicationDefinedRecordNapi::NewInstance(env, in, out);
223             break;
224         }
225         default:
226             UnifiedRecordNapi::NewInstance(env, in, out);
227             LOG_INFO(UDMF_KITS_NAPI, "GetRecord default");
228             break;
229     }
230 }
231 
HasType(napi_env env,napi_callback_info info)232 napi_value UnifiedDataNapi::HasType(napi_env env, napi_callback_info info)
233 {
234     LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedDataNapi");
235     std::string type;
236     auto ctxt = std::make_shared<ContextBase>();
237     auto input = [env, info, ctxt, &type](size_t argc, napi_value *argv) {
238         ASSERT_BUSINESS_ERR(ctxt, argc >= 1,
239             Status::E_INVALID_PARAMETERS, "Parameter error: Mandatory parameters are left unspecified");
240         ctxt->status = NapiDataUtils::GetValue(env, argv[0], type);
241         ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok,
242             Status::E_INVALID_PARAMETERS, "Parameter error: parameter type type must be string");
243     };
244     ctxt->GetCbInfoSync(env, info, input);
245     ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_ERROR, ctxt->error);
246     auto *uData = static_cast<UnifiedDataNapi *>(ctxt->native);
247     ASSERT_ERR(
248         ctxt->env, (uData != nullptr && uData->value_ != nullptr), Status::E_ERROR, "invalid object!");
249     bool ret = uData->value_->HasType(type);
250     napi_value result = nullptr;
251     napi_get_boolean(env, ret, &result);
252     return result;
253 }
254 
GetTypes(napi_env env,napi_callback_info info)255 napi_value UnifiedDataNapi::GetTypes(napi_env env, napi_callback_info info)
256 {
257     LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedDataNapi");
258     auto uData = GetUnifiedData(env, info);
259     ASSERT_ERR(env, (uData != nullptr && uData->value_ != nullptr), Status::E_ERROR, "invalid object!");
260 
261     std::vector<std::string> Types = uData->value_->GetTypesLabels();
262     napi_value nTypes = nullptr;
263     napi_status status = napi_create_array(env, &nTypes);
264     ASSERT_ERR(env, status == napi_ok, Status::E_ERROR, "create array fail!");
265 
266     size_t index = 0;
267     napi_value value = nullptr;
268     for (auto type : Types) {
269         napi_create_string_utf8(env, type.c_str(), NAPI_AUTO_LENGTH, &value);
270         napi_set_element(env, nTypes, index, value);
271         index++;
272     }
273     return nTypes;
274 }
275 
GetProperties(napi_env env,napi_callback_info info)276 napi_value UnifiedDataNapi::GetProperties(napi_env env, napi_callback_info info)
277 {
278     LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedDataNapi");
279     napi_value value;
280     auto uData = GetUnifiedData(env, info);
281     ASSERT_ERR(env, (uData != nullptr && uData->value_ != nullptr), Status::E_ERROR, "invalid object!");
282     NAPI_CALL(env, napi_get_reference_value(env, uData->propertyRef_, &value));
283     return value;
284 }
285 
GetPropertiesNapi(napi_env env)286 UnifiedDataPropertiesNapi* UnifiedDataNapi::GetPropertiesNapi(napi_env env)
287 {
288     napi_value value;
289     NAPI_CALL(env, napi_get_reference_value(env, propertyRef_, &value));
290     UnifiedDataPropertiesNapi* out = nullptr;
291     napi_status status = napi_unwrap(env, value, reinterpret_cast<void**>(&out));
292     ASSERT_ERR(env, status == napi_ok && out != nullptr, Status::E_ERROR, "napi_unwrap failed");
293     return out;
294 }
295 
SetProperties(napi_env env,napi_callback_info info)296 napi_value UnifiedDataNapi::SetProperties(napi_env env, napi_callback_info info)
297 {
298     LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedDataNapi");
299     auto ctxt = std::make_shared<ContextBase>();
300     auto input = [env, ctxt](size_t argc, napi_value* argv) {
301         ASSERT_BUSINESS_ERR(ctxt, argc >= 1,
302             Status::E_INVALID_PARAMETERS, "Parameter error: Mandatory parameters are left unspecified");
303         UnifiedDataPropertiesNapi* propertiesNapi = nullptr;
304         ctxt->status = Unwrap(env, argv[0], reinterpret_cast<void**>(&propertiesNapi),
305             UnifiedDataPropertiesNapi::Constructor(env));
306         ASSERT_BUSINESS_ERR(ctxt, propertiesNapi != nullptr,
307             Status::E_INVALID_PARAMETERS, "Parameter error: parameter properties type must be UnifiedDataProperties");
308 
309         auto uData = static_cast<UnifiedDataNapi*>(ctxt->native);
310         if (uData->propertyRef_ != nullptr) {
311             napi_delete_reference(env, uData->propertyRef_);
312         }
313         ctxt->status = napi_create_reference(env, argv[0], 1, &uData->propertyRef_);
314         ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok,
315             Status::E_ERROR, "napi_create_reference to properties failed!");
316         uData->value_->SetProperties(propertiesNapi->value_);
317     };
318     ctxt->GetCbInfoSync(env, info, input);
319     ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_ERROR, ctxt->error);
320     return ctxt->self;
321 }
322 
NewWithRef(napi_env env,size_t argc,napi_value * argv,void ** out,napi_value constructor)323 napi_ref UnifiedDataNapi::NewWithRef(napi_env env, size_t argc, napi_value *argv, void **out, napi_value constructor)
324 {
325     napi_value object = nullptr;
326     napi_status status = napi_new_instance(env, constructor, argc, argv, &object);
327     ASSERT_ERR(env, status == napi_ok && object != nullptr, Status::E_ERROR, "napi_new_instance failed");
328 
329     status = napi_unwrap(env, object, out);
330     ASSERT_ERR(env, status == napi_ok && out != nullptr, Status::E_ERROR, "napi_unwrap failed");
331 
332     napi_ref ref = nullptr;
333     status = napi_create_reference(env, object, 1, &ref);
334     ASSERT_ERR(env, status == napi_ok && ref != nullptr, Status::E_ERROR, "napi_create_reference failed");
335     return ref;
336 }
337 
Unwrap(napi_env env,napi_value in,void ** out,napi_value constructor)338 napi_status UnifiedDataNapi::Unwrap(napi_env env, napi_value in, void **out, napi_value constructor)
339 {
340     if (constructor != nullptr) {
341         bool isInstance = false;
342         napi_instanceof(env, in, constructor, &isInstance);
343         if (!isInstance) {
344             LOG_ERROR(UDMF_KITS_NAPI, "not a instance of *");
345             return napi_invalid_arg;
346         }
347     }
348     return napi_unwrap(env, in, out);
349 }
350 } // namespace UDMF
351 } // namespace OHOS