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