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