• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "UnifiedRecordNapi"
16 #include "unified_record_napi.h"
17 
18 #include "plain_text.h"
19 #include "html.h"
20 #include "link.h"
21 #include "image.h"
22 #include "video.h"
23 #include "audio.h"
24 #include "folder.h"
25 #include "system_defined_appitem.h"
26 #include "system_defined_form.h"
27 #include "system_defined_pixelmap.h"
28 #include "application_defined_record.h"
29 
30 namespace OHOS {
31 namespace UDMF {
Constructor(napi_env env)32 napi_value UnifiedRecordNapi::Constructor(napi_env env)
33 {
34     LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedRecordNapi");
35     napi_property_descriptor properties[] = {
36         /* UnifiedRecord properties */
37         DECLARE_NAPI_FUNCTION("getType", GetType),
38         DECLARE_NAPI_FUNCTION("getValue", GetValue),
39         DECLARE_NAPI_FUNCTION("addEntry", AddEntry),
40         DECLARE_NAPI_FUNCTION("getEntry", GetEntry),
41         DECLARE_NAPI_FUNCTION("getEntries", GetEntries),
42         DECLARE_NAPI_FUNCTION("getTypes", GetTypes),
43     };
44     size_t count = sizeof(properties) / sizeof(properties[0]);
45     return NapiDataUtils::DefineClass(env, "UnifiedRecord", properties, count, UnifiedRecordNapi::New);
46 }
47 
New(napi_env env,napi_callback_info info)48 napi_value UnifiedRecordNapi::New(napi_env env, napi_callback_info info)
49 {
50     LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedRecordNapi");
51     auto ctxt = std::make_shared<ContextBase>();
52     std::string type;
53     napi_value value = nullptr;
54     auto input = [env, ctxt, &type, &value](size_t argc, napi_value *argv) {
55         ASSERT_BUSINESS_ERR(ctxt, argc == 0 || argc >= 2,
56             Status::E_INVALID_PARAMETERS, "Parameter error: Mandatory parameters are left unspecified");
57         if (argc >= 2) {
58             ctxt->status = NapiDataUtils::GetValue(env, argv[0], type);
59             ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok && !type.empty(),
60                 Status::E_INVALID_PARAMETERS, "Parameter error: parameter type must be string");
61             value = argv[1];
62         }
63     };
64     ctxt->GetCbInfoSync(env, info, input);
65     ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_ERROR, ctxt->error);
66 
67     auto *udRecord = new (std::nothrow) UnifiedRecordNapi();
68     ASSERT_ERR(ctxt->env, udRecord != nullptr, Status::E_ERROR, "no memory for unified record!");
69     if (value != nullptr) {
70         udRecord->value_ = GenerateNativeRecord(env, type, value);
71     } else {
72         udRecord->value_ = std::make_shared<UnifiedRecord>();
73     }
74     ASSERT_CALL(env, napi_wrap(env, ctxt->self, udRecord, Destructor, nullptr, nullptr), udRecord);
75     return ctxt->self;
76 }
77 
GenerateNativeRecord(napi_env env,std::string type,napi_value valueNapi)78 std::shared_ptr<UnifiedRecord> UnifiedRecordNapi::GenerateNativeRecord(napi_env env, std::string type,
79     napi_value valueNapi)
80 {
81     LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedRecordNapi");
82     ValueType value;
83     GetNativeValue(env, type, valueNapi, value);
84 
85     UDType utdType = APPLICATION_DEFINED_RECORD;
86     if (UtdUtils::IsValidUtdId(type)) {
87         utdType = static_cast<UDType>(UtdUtils::GetUtdEnumFromUtdId(type));
88     }
89 
90     std::map<UDType, std::function<std::shared_ptr<UnifiedRecord>(UDType, ValueType)>> constructors = {
91         {TEXT, [](UDType type, ValueType value) { return std::make_shared<Text>(type, value); }},
92         {PLAIN_TEXT, [](UDType type, ValueType value) { return std::make_shared<PlainText>(type, value); }},
93         {HTML, [](UDType type, ValueType value) { return std::make_shared<Html>(type, value); }},
94         {HYPERLINK, [](UDType type, ValueType value) { return std::make_shared<Link>(type, value); }},
95         {FILE, [](UDType type, ValueType value) { return std::make_shared<File>(type, value); }},
96         {IMAGE, [](UDType type, ValueType value) { return std::make_shared<Image>(type, value); }},
97         {VIDEO, [](UDType type, ValueType value) { return std::make_shared<Video>(type, value); }},
98         {AUDIO, [](UDType type, ValueType value) { return std::make_shared<Audio>(type, value); }},
99         {FOLDER, [](UDType type, ValueType value) { return std::make_shared<Folder>(type, value); }},
100         {SYSTEM_DEFINED_RECORD,
101             [](UDType type, ValueType value) { return std::make_shared<SystemDefinedRecord>(type, value); }},
102         {SYSTEM_DEFINED_APP_ITEM,
103             [](UDType type, ValueType value) { return std::make_shared<SystemDefinedAppItem>(type, value); }},
104         {SYSTEM_DEFINED_FORM,
105             [](UDType type, ValueType value) { return std::make_shared<SystemDefinedForm>(type, value); }},
106         {SYSTEM_DEFINED_PIXEL_MAP,
107             [](UDType type, ValueType value) { return std::make_shared<SystemDefinedPixelMap>(type, value); }},
108         {APPLICATION_DEFINED_RECORD,
109             [](UDType type, ValueType value) { return std::make_shared<ApplicationDefinedRecord>(type, value); }},
110     };
111 
112     auto constructor = constructors.find(utdType);
113     if (constructor == constructors.end()) {
114         return std::make_shared<UnifiedRecord>(utdType, value);
115     }
116     auto uRecord = constructor->second(utdType, value);
117     if (utdType == APPLICATION_DEFINED_RECORD) {
118         std::shared_ptr<ApplicationDefinedRecord> applicationDefinedRecord =
119             std::static_pointer_cast<ApplicationDefinedRecord>(uRecord);
120         applicationDefinedRecord->SetApplicationDefinedType(type);
121     }
122     return uRecord;
123 }
124 
GetNativeValue(napi_env env,std::string type,napi_value valueNapi,ValueType & value)125 void UnifiedRecordNapi::GetNativeValue(napi_env env, std::string type, napi_value valueNapi, ValueType &value)
126 {
127     bool isArrayBuffer = false;
128     NAPI_CALL_RETURN_VOID(env, napi_is_arraybuffer(env, valueNapi, &isArrayBuffer));
129     if (isArrayBuffer) {
130         void *data = nullptr;
131         size_t dataLen = 0;
132         NAPI_CALL_RETURN_VOID(env, napi_get_arraybuffer_info(env, valueNapi, &data, &dataLen));
133         value = std::vector<uint8_t>(reinterpret_cast<uint8_t *>(data), reinterpret_cast<uint8_t *>(data) + dataLen);
134         return;
135     }
136 
137     napi_status status;
138     napi_valuetype valueType = napi_undefined;
139     status = napi_typeof(env, valueNapi, &valueType);
140     ASSERT_ERR_VOID(env, status == napi_ok,
141         Status::E_INVALID_PARAMETERS, "Parameter error: parameter value type must be ValueType");
142     if (valueType == napi_object) {
143         ProcessNapiObject(env, type, valueNapi, value);
144     } else if (valueType == napi_string) {
145         value = std::string();
146     } else if (valueType == napi_number) {
147         value = double();
148     } else if (valueType == napi_boolean) {
149         value = bool();
150     } else if (valueType == napi_undefined) {
151         value = std::monostate();
152     } else if (valueType == napi_null) {
153         value = nullptr;
154     }
155     std::visit([&](auto &value) { status = NapiDataUtils::GetValue(env, valueNapi, value); }, value);
156     ASSERT_ERR_VOID(env, status == napi_ok, Status::E_ERROR, "get unifiedRecord failed");
157 }
158 
ProcessNapiObject(napi_env env,std::string type,napi_value valueNapi,ValueType & value)159 void UnifiedRecordNapi::ProcessNapiObject(napi_env env, std::string type, napi_value valueNapi, ValueType &value)
160 {
161     if (type == "openharmony.pixel-map") {
162         napi_value attrName = nullptr;
163         napi_value attrVal = nullptr;
164         const std::string uniformDataType = "uniformDataType";
165         napi_status status = NapiDataUtils::SetValue(env, uniformDataType, attrName);
166         ASSERT_ERR_VOID(env, status == napi_ok, Status::E_ERROR, "set attrName failed");
167         status = napi_get_property(env, valueNapi, attrName, &attrVal);
168         if (status == napi_ok) {
169             std::string proVal;
170             status = NapiDataUtils::GetValue(env, attrVal, proVal);
171             if (status == napi_ok && proVal == "openharmony.pixel-map") {
172                 value = std::make_shared<Object>();
173             } else {
174                 value = std::shared_ptr<OHOS::Media::PixelMap>(nullptr);
175             }
176         }
177     } else if (type == "openharmony.want") {
178         value = std::shared_ptr<OHOS::AAFwk::Want>(nullptr);
179     } else {
180         value = std::make_shared<Object>();
181     }
182 }
183 
NewInstance(napi_env env,std::shared_ptr<UnifiedRecord> in,napi_value & out)184 void UnifiedRecordNapi::NewInstance(napi_env env, std::shared_ptr<UnifiedRecord> in, napi_value &out)
185 {
186     LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedRecordNapi");
187     ASSERT_CALL_VOID(env, napi_new_instance(env, Constructor(env), 0, nullptr, &out));
188     auto *record = new (std::nothrow) UnifiedRecordNapi();
189     ASSERT_ERR_VOID(env, record != nullptr, Status::E_ERROR, "no memory for unified record");
190     record->value_ = in;
191     ASSERT_CALL_DELETE(env, napi_wrap(env, out, record, Destructor, nullptr, nullptr), record);
192 }
193 
Destructor(napi_env env,void * data,void * hint)194 void UnifiedRecordNapi::Destructor(napi_env env, void *data, void *hint)
195 {
196     LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedRecordNapi finalize.");
197     auto *uRecord = static_cast<UnifiedRecordNapi *>(data);
198     ASSERT_VOID(uRecord != nullptr, "finalize null!");
199     delete uRecord;
200 }
201 
GetUnifiedRecord(napi_env env,napi_callback_info info,std::shared_ptr<ContextBase> ctxt)202 UnifiedRecordNapi *UnifiedRecordNapi::GetUnifiedRecord(
203     napi_env env, napi_callback_info info, std::shared_ptr<ContextBase> ctxt)
204 {
205     LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedRecordNapi");
206     ctxt->GetCbInfoSync(env, info);
207     ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_ERROR, ctxt->error);
208     return static_cast<UnifiedRecordNapi *>(ctxt->native);
209 }
210 
GetType(napi_env env,napi_callback_info info)211 napi_value UnifiedRecordNapi::GetType(napi_env env, napi_callback_info info)
212 {
213     LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedRecordNapi");
214     auto ctxt = std::make_shared<ContextBase>();
215     auto uRecord = GetUnifiedRecord(env, info, ctxt);
216     ASSERT_ERR(ctxt->env, (uRecord != nullptr && uRecord->value_ != nullptr), Status::E_ERROR, "invalid object!");
217     ctxt->status = NapiDataUtils::SetValue(env, UtdUtils::GetUtdIdFromUtdEnum(uRecord->value_->GetType()),
218                                            ctxt->output);
219     ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_ERROR, "set type failed!");
220     return ctxt->output;
221 }
222 
GetTypes(napi_env env,napi_callback_info info)223 napi_value UnifiedRecordNapi::GetTypes(napi_env env, napi_callback_info info)
224 {
225     LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedRecordNapi");
226     auto ctxt = std::make_shared<ContextBase>();
227     auto uRecord = GetUnifiedRecord(env, info, ctxt);
228     ASSERT_ERR(ctxt->env, (uRecord != nullptr && uRecord->value_ != nullptr), Status::E_ERROR, "invalid object!");
229     ctxt->status = NapiDataUtils::SetValue(env, uRecord->value_->GetTypes(), ctxt->output);
230     ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_ERROR, "set type failed!");
231     return ctxt->output;
232 }
233 
GetValue(napi_env env,napi_callback_info info)234 napi_value UnifiedRecordNapi::GetValue(napi_env env, napi_callback_info info)
235 {
236     LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedRecordNapi");
237     auto ctxt = std::make_shared<ContextBase>();
238     auto uRecord = GetUnifiedRecord(env, info, ctxt);
239     ASSERT_ERR(ctxt->env, (uRecord != nullptr && uRecord->value_ != nullptr), Status::E_ERROR, "invalid object!");
240     if (std::holds_alternative<std::vector<uint8_t>>(uRecord->value_->GetValue())) {
241         auto value = std::get<std::vector<uint8_t>>(uRecord->value_->GetValue());
242         void *data = nullptr;
243         size_t len = value.size();
244         NAPI_CALL(env, napi_create_arraybuffer(env, len, &data, &ctxt->output));
245         if (memcpy_s(data, len, reinterpret_cast<const void *>(value.data()), len) != 0) {
246             LOG_ERROR(UDMF_KITS_NAPI, "memcpy_s failed");
247             return nullptr;
248         }
249     } else {
250         std::visit([&](const auto &value) { NapiDataUtils::SetValue(env, value, ctxt->output); },
251             uRecord->value_->GetValue());
252     }
253     return ctxt->output;
254 }
255 
AddEntry(napi_env env,napi_callback_info info)256 napi_value UnifiedRecordNapi::AddEntry(napi_env env, napi_callback_info info)
257 {
258     LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedRecordNapi");
259     auto ctxt = std::make_shared<ContextBase>();
260     std::string type;
261     napi_value napiValue = nullptr;
262     auto input = [env, ctxt, &type, &napiValue](size_t argc, napi_value *argv) {
263         ASSERT_BUSINESS_ERR(ctxt, argc == 0 || argc >= 2,
264             Status::E_INVALID_PARAMETERS, "Parameter error: Mandatory parameters are left unspecified");
265         if (argc >= 2) {
266             ctxt->status = NapiDataUtils::GetValue(env, argv[0], type);
267             ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok && !type.empty(),
268                 Status::E_INVALID_PARAMETERS, "Parameter error: parameter type must be string");
269             napiValue = argv[1];
270         }
271     };
272     ctxt->GetCbInfoSync(env, info, input);
273     ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_ERROR, ctxt->error);
274     auto uRecord = static_cast<UnifiedRecordNapi *>(ctxt->native);
275     ASSERT_ERR(ctxt->env, (uRecord != nullptr && uRecord->value_ != nullptr), Status::E_ERROR, "invalid object!");
276     ValueType value;
277     GetNativeValue(env, type, napiValue, value);
278     uRecord->value_->AddEntry(type, std::move(value));
279     return nullptr;
280 }
281 
GetEntry(napi_env env,napi_callback_info info)282 napi_value UnifiedRecordNapi::GetEntry(napi_env env, napi_callback_info info)
283 {
284     LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedRecordNapi");
285     auto ctxt = std::make_shared<ContextBase>();
286     std::string type;
287     auto input = [env, ctxt, &type](size_t argc, napi_value *argv) {
288         ASSERT_BUSINESS_ERR(ctxt, argc == 0 || argc >= 1,
289             Status::E_INVALID_PARAMETERS, "Parameter error: Mandatory parameters are left unspecified");
290         if (argc >= 1) {
291             ctxt->status = NapiDataUtils::GetValue(env, argv[0], type);
292             ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok && !type.empty(),
293                 Status::E_INVALID_PARAMETERS, "Parameter error: parameter type must be string");
294         }
295     };
296     ctxt->GetCbInfoSync(env, info, input);
297     ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_ERROR, ctxt->error);
298     auto uRecord = static_cast<UnifiedRecordNapi *>(ctxt->native);
299     ASSERT_ERR(ctxt->env, (uRecord != nullptr && uRecord->value_ != nullptr), Status::E_ERROR, "invalid object!");
300     ValueType entry = uRecord->value_->GetEntry(type);
301     if (std::holds_alternative<std::vector<uint8_t>>(entry)) {
302         auto value = std::get<std::vector<uint8_t>>(entry);
303         void *data = nullptr;
304         size_t len = value.size();
305         NAPI_CALL(env, napi_create_arraybuffer(env, len, &data, &ctxt->output));
306         if (memcpy_s(data, len, reinterpret_cast<const void *>(value.data()), len) != 0) {
307             LOG_ERROR(UDMF_KITS_NAPI, "memcpy_s failed");
308             return nullptr;
309         }
310     } else {
311         std::visit([&](const auto &value) { NapiDataUtils::SetValue(env, value, ctxt->output); },
312             entry);
313     }
314     return ctxt->output;
315 }
316 
GetEntries(napi_env env,napi_callback_info info)317 napi_value UnifiedRecordNapi::GetEntries(napi_env env, napi_callback_info info)
318 {
319     LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedRecordNapi");
320     auto ctxt = std::make_shared<ContextBase>();
321     auto uRecord = GetUnifiedRecord(env, info, ctxt);
322     ASSERT_ERR(ctxt->env, (uRecord != nullptr && uRecord->value_ != nullptr), Status::E_ERROR, "invalid object!");
323     std::shared_ptr<std::map<std::string, ValueType>> entries = uRecord->value_->GetEntries();
324     napi_create_object(env, &ctxt->output);
325     for (auto &entry : *entries) {
326         napi_value napiValue = nullptr;
327         if (std::holds_alternative<std::vector<uint8_t>>(entry.second)) {
328             auto vecVal = std::get<std::vector<uint8_t>>(entry.second);
329             void *data = nullptr;
330             size_t len = vecVal.size();
331             NAPI_CALL(env, napi_create_arraybuffer(env, len, &data, &napiValue));
332             if (memcpy_s(data, len, reinterpret_cast<const void *>(vecVal.data()), len) != 0) {
333                 LOG_ERROR(UDMF_KITS_NAPI, "memcpy_s failed");
334                 return nullptr;
335             }
336         } else {
337             std::visit([&](const auto &value) { NapiDataUtils::SetValue(env, value, napiValue); },
338                 entry.second);
339         }
340         napi_set_named_property(env, ctxt->output, entry.first.c_str(), napiValue);
341     }
342     return ctxt->output;
343 }
344 } // namespace UDMF
345 } // namespace OHOS