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 };
40 size_t count = sizeof(properties) / sizeof(properties[0]);
41 return NapiDataUtils::DefineClass(env, "UnifiedRecord", properties, count, UnifiedRecordNapi::New);
42 }
43
New(napi_env env,napi_callback_info info)44 napi_value UnifiedRecordNapi::New(napi_env env, napi_callback_info info)
45 {
46 LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedRecordNapi");
47 auto ctxt = std::make_shared<ContextBase>();
48 std::string type;
49 napi_value value = nullptr;
50 auto input = [env, ctxt, &type, &value](size_t argc, napi_value *argv) {
51 ASSERT_BUSINESS_ERR(ctxt, argc == 0 || argc >= 2,
52 Status::E_INVALID_PARAMETERS, "Parameter error: Mandatory parameters are left unspecified");
53 if (argc >= 2) {
54 ctxt->status = NapiDataUtils::GetValue(env, argv[0], type);
55 ASSERT_BUSINESS_ERR(ctxt, ctxt->status == napi_ok && !type.empty(),
56 Status::E_INVALID_PARAMETERS, "Parameter error: parameter type type must be string");
57 value = argv[1];
58 }
59 };
60 ctxt->GetCbInfoSync(env, info, input);
61 ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_ERROR, ctxt->error);
62
63 auto *udRecord = new (std::nothrow) UnifiedRecordNapi();
64 ASSERT_ERR(ctxt->env, udRecord != nullptr, Status::E_ERROR, "no memory for unified record!");
65 if (value != nullptr) {
66 udRecord->value_ = GenerateNativeRecord(env, type, value);
67 } else {
68 udRecord->value_ = std::make_shared<UnifiedRecord>();
69 }
70 ASSERT_CALL(env, napi_wrap(env, ctxt->self, udRecord, Destructor, nullptr, nullptr), udRecord);
71 return ctxt->self;
72 }
73
GenerateNativeRecord(napi_env env,std::string type,napi_value valueNapi)74 std::shared_ptr<UnifiedRecord> UnifiedRecordNapi::GenerateNativeRecord(napi_env env, std::string type,
75 napi_value valueNapi)
76 {
77 LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedRecordNapi");
78 ValueType value;
79 GetNativeValue(env, type, valueNapi, value);
80
81 UDType utdType = APPLICATION_DEFINED_RECORD;
82 if (UtdUtils::IsValidUtdId(type)) {
83 utdType = static_cast<UDType>(UtdUtils::GetUtdEnumFromUtdId(type));
84 }
85
86 std::map<UDType, std::function<std::shared_ptr<UnifiedRecord>(UDType, ValueType)>> constructors = {
87 {TEXT, [](UDType type, ValueType value) { return std::make_shared<Text>(type, value); }},
88 {PLAIN_TEXT, [](UDType type, ValueType value) { return std::make_shared<PlainText>(type, value); }},
89 {HTML, [](UDType type, ValueType value) { return std::make_shared<Html>(type, value); }},
90 {HYPERLINK, [](UDType type, ValueType value) { return std::make_shared<Link>(type, value); }},
91 {FILE, [](UDType type, ValueType value) { return std::make_shared<File>(type, value); }},
92 {IMAGE, [](UDType type, ValueType value) { return std::make_shared<Image>(type, value); }},
93 {VIDEO, [](UDType type, ValueType value) { return std::make_shared<Video>(type, value); }},
94 {AUDIO, [](UDType type, ValueType value) { return std::make_shared<Audio>(type, value); }},
95 {FOLDER, [](UDType type, ValueType value) { return std::make_shared<Folder>(type, value); }},
96 {SYSTEM_DEFINED_RECORD,
97 [](UDType type, ValueType value) { return std::make_shared<SystemDefinedRecord>(type, value); }},
98 {SYSTEM_DEFINED_APP_ITEM,
99 [](UDType type, ValueType value) { return std::make_shared<SystemDefinedAppItem>(type, value); }},
100 {SYSTEM_DEFINED_FORM,
101 [](UDType type, ValueType value) { return std::make_shared<SystemDefinedForm>(type, value); }},
102 {SYSTEM_DEFINED_PIXEL_MAP,
103 [](UDType type, ValueType value) { return std::make_shared<SystemDefinedPixelMap>(type, value); }},
104 {APPLICATION_DEFINED_RECORD,
105 [](UDType type, ValueType value) { return std::make_shared<ApplicationDefinedRecord>(type, value); }},
106 };
107
108 auto constructor = constructors.find(utdType);
109 if (constructor == constructors.end()) {
110 return std::make_shared<UnifiedRecord>(utdType, value);
111 }
112 auto uRecord = constructor->second(utdType, value);
113 if (utdType == APPLICATION_DEFINED_RECORD) {
114 std::shared_ptr<ApplicationDefinedRecord> applicationDefinedRecord =
115 std::static_pointer_cast<ApplicationDefinedRecord>(uRecord);
116 applicationDefinedRecord->SetApplicationDefinedType(type);
117 }
118 return uRecord;
119 }
120
GetNativeValue(napi_env env,std::string type,napi_value valueNapi,ValueType & value)121 void UnifiedRecordNapi::GetNativeValue(napi_env env, std::string type, napi_value valueNapi, ValueType &value)
122 {
123 bool isArrayBuffer = false;
124 NAPI_CALL_RETURN_VOID(env, napi_is_arraybuffer(env, valueNapi, &isArrayBuffer));
125 if (isArrayBuffer) {
126 void *data = nullptr;
127 size_t dataLen = 0;
128 NAPI_CALL_RETURN_VOID(env, napi_get_arraybuffer_info(env, valueNapi, &data, &dataLen));
129 value = std::vector<uint8_t>(reinterpret_cast<uint8_t *>(data), reinterpret_cast<uint8_t *>(data) + dataLen);
130 return;
131 }
132
133 napi_status status;
134 napi_valuetype valueType = napi_undefined;
135 status = napi_typeof(env, valueNapi, &valueType);
136 ASSERT_ERR_VOID(env, status == napi_ok,
137 Status::E_INVALID_PARAMETERS, "Parameter error: parameter value type must be ValueType");
138 if (valueType == napi_object) {
139 if (type == "openharmony.pixel-map") {
140 value = std::shared_ptr<OHOS::Media::PixelMap>(nullptr);
141 } else if (type == "openharmony.want") {
142 value = std::shared_ptr<OHOS::AAFwk::Want>(nullptr);
143 } else {
144 value = std::make_shared<Object>();
145 }
146 } else if (valueType == napi_string) {
147 value = std::string();
148 } else if (valueType == napi_number) {
149 value = double();
150 } else if (valueType == napi_boolean) {
151 value = bool();
152 } else if (valueType == napi_undefined) {
153 value = std::monostate();
154 } else if (valueType == napi_null) {
155 value = nullptr;
156 }
157 std::visit([&](auto &value) { status = NapiDataUtils::GetValue(env, valueNapi, value); }, value);
158 ASSERT_ERR_VOID(env, status == napi_ok, Status::E_ERROR, "get unifiedRecord failed");
159 }
160
NewInstance(napi_env env,std::shared_ptr<UnifiedRecord> in,napi_value & out)161 void UnifiedRecordNapi::NewInstance(napi_env env, std::shared_ptr<UnifiedRecord> in, napi_value &out)
162 {
163 LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedRecordNapi");
164 ASSERT_CALL_VOID(env, napi_new_instance(env, Constructor(env), 0, nullptr, &out));
165 auto *record = new (std::nothrow) UnifiedRecordNapi();
166 ASSERT_ERR_VOID(env, record != nullptr, Status::E_ERROR, "no memory for unified record");
167 record->value_ = in;
168 ASSERT_CALL_DELETE(env, napi_wrap(env, out, record, Destructor, nullptr, nullptr), record);
169 }
170
Destructor(napi_env env,void * data,void * hint)171 void UnifiedRecordNapi::Destructor(napi_env env, void *data, void *hint)
172 {
173 LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedRecordNapi finalize.");
174 auto *uRecord = static_cast<UnifiedRecordNapi *>(data);
175 ASSERT_VOID(uRecord != nullptr, "finalize null!");
176 delete uRecord;
177 }
178
GetUnifiedRecord(napi_env env,napi_callback_info info,std::shared_ptr<ContextBase> ctxt)179 UnifiedRecordNapi *UnifiedRecordNapi::GetUnifiedRecord(
180 napi_env env, napi_callback_info info, std::shared_ptr<ContextBase> ctxt)
181 {
182 LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedRecordNapi");
183 ctxt->GetCbInfoSync(env, info);
184 ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_ERROR, ctxt->error);
185 return static_cast<UnifiedRecordNapi *>(ctxt->native);
186 }
187
GetType(napi_env env,napi_callback_info info)188 napi_value UnifiedRecordNapi::GetType(napi_env env, napi_callback_info info)
189 {
190 LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedRecordNapi");
191 auto ctxt = std::make_shared<ContextBase>();
192 auto uRecord = GetUnifiedRecord(env, info, ctxt);
193 ASSERT_ERR(ctxt->env, (uRecord != nullptr && uRecord->value_ != nullptr), Status::E_ERROR, "invalid object!");
194 ctxt->status = NapiDataUtils::SetValue(env, UtdUtils::GetUtdIdFromUtdEnum(uRecord->value_->GetType()),
195 ctxt->output);
196 ASSERT_ERR(ctxt->env, ctxt->status == napi_ok, Status::E_ERROR, "set type failed!");
197 return ctxt->output;
198 }
199
GetValue(napi_env env,napi_callback_info info)200 napi_value UnifiedRecordNapi::GetValue(napi_env env, napi_callback_info info)
201 {
202 LOG_DEBUG(UDMF_KITS_NAPI, "UnifiedRecordNapi");
203 auto ctxt = std::make_shared<ContextBase>();
204 auto uRecord = GetUnifiedRecord(env, info, ctxt);
205 ASSERT_ERR(ctxt->env, (uRecord != nullptr && uRecord->value_ != nullptr), Status::E_ERROR, "invalid object!");
206 if (std::holds_alternative<std::vector<uint8_t>>(uRecord->value_->GetValue())) {
207 auto value = std::get<std::vector<uint8_t>>(uRecord->value_->GetValue());
208 void *data = nullptr;
209 size_t len = value.size();
210 NAPI_CALL(env, napi_create_arraybuffer(env, len, &data, &ctxt->output));
211 if (memcpy_s(data, len, reinterpret_cast<const void *>(value.data()), len) != 0) {
212 LOG_ERROR(UDMF_KITS_NAPI, "memcpy_s failed");
213 return nullptr;
214 }
215 } else {
216 std::visit([&](const auto &value) { NapiDataUtils::SetValue(env, value, ctxt->output); },
217 uRecord->value_->GetValue());
218 }
219 return ctxt->output;
220 }
221 } // namespace UDMF
222 } // namespace OHOS