1 /*
2  * Copyright (c) 2024 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 #include "rstate.h"
16 #include "napi/native_api.h"
17 #include "napi/native_node_api.h"
18 #include "native_engine.h"
19 #include "../../../../frameworks/resmgr/include/hilog_wrapper.h"
20 
21 namespace OHOS {
22 namespace Global {
23 namespace Resource {
24 #define GET_PARAMS(env, info, num)    \
25     size_t argc = num;                \
26     napi_value argv[num] = {nullptr}; \
27     napi_value thisVar = nullptr;     \
28     void *data = nullptr;             \
29     napi_get_cb_info(env, info, &argc, argv, &thisVar, &data)
30 
IsNapiObject(napi_env env,napi_callback_info info)31 static bool IsNapiObject(napi_env env, napi_callback_info info)
32 {
33     GET_PARAMS(env, info, 1);
34     napi_valuetype valueType = napi_valuetype::napi_undefined;
35     napi_typeof(env, argv[0], &valueType);
36     if (valueType != napi_object) {
37         RESMGR_HILOGW(RESMGR_JS_TAG, "Parameter type is not napi_object");
38         return false;
39     }
40     return true;
41 }
42 
NapiThrow(napi_env env,int32_t errCode)43 static void NapiThrow(napi_env env, int32_t errCode)
44 {
45     napi_value code = nullptr;
46     napi_create_string_latin1(env, std::to_string(errCode).c_str(), NAPI_AUTO_LENGTH, &code);
47 
48     napi_value message = nullptr;
49     std::string errMsg = "Invalid input parameter";
50     napi_create_string_latin1(env, errMsg.c_str(), NAPI_AUTO_LENGTH, &message);
51     if (message != nullptr) {
52         napi_value error = nullptr;
53         napi_create_error(env, code, message, &error);
54         napi_throw(env, error);
55     }
56 }
57 
GetResourceProp(napi_env env,napi_callback_info info,std::vector<napi_value> & props)58 static bool GetResourceProp(napi_env env, napi_callback_info info, std::vector<napi_value> &props)
59 {
60     if (!IsNapiObject(env, info)) {
61         RESMGR_HILOGE(RESMGR_JS_TAG, "Failed to get resource object");
62         return false;
63     }
64     GET_PARAMS(env, info, 1);
65     napi_value bundleName = nullptr;
66     napi_valuetype bundleNameType = napi_undefined;
67     if (napi_get_named_property(env, argv[0], "bundleName", &bundleName) != napi_ok ||
68         napi_typeof(env, bundleName, &bundleNameType) != napi_ok || bundleNameType != napi_string) {
69         RESMGR_HILOGE(RESMGR_JS_TAG, "Failed to get resource bundleName property");
70         return false;
71     }
72 
73     napi_value moduleName = nullptr;
74     napi_valuetype moduleNameType = napi_undefined;
75     if (napi_get_named_property(env, argv[0], "moduleName", &moduleName) != napi_ok ||
76         napi_typeof(env, moduleName, &moduleNameType) != napi_ok || moduleNameType != napi_string) {
77         RESMGR_HILOGE(RESMGR_JS_TAG, "Failed to get resource moduleName property");
78         return false;
79     }
80 
81     napi_value id = nullptr;
82     napi_valuetype idType = napi_undefined;
83     if (napi_get_named_property(env, argv[0], "id", &id) != napi_ok ||
84         napi_typeof(env, id, &idType) != napi_ok || idType != napi_number) {
85         RESMGR_HILOGE(RESMGR_JS_TAG, "Failed to get resource id property");
86         return false;
87     }
88 
89     napi_value params = nullptr;
90     if (napi_get_named_property(env, argv[0], "params", &params) != napi_ok) {
91         RESMGR_HILOGE(RESMGR_JS_TAG, "Failed to get resource params property");
92         return false;
93     }
94 
95     napi_value type = nullptr;
96     if (napi_get_named_property(env, argv[0], "type", &type) != napi_ok) {
97         RESMGR_HILOGE(RESMGR_JS_TAG, "Failed to get resource type property");
98         return false;
99     }
100     props.emplace_back(bundleName);
101     props.emplace_back(moduleName);
102     props.emplace_back(id);
103     props.emplace_back(params);
104     props.emplace_back(type);
105     return true;
106 }
107 
GetParams(napi_env env,napi_value params,napi_value * newParams,bool isSendable)108 static bool GetParams(napi_env env, napi_value params, napi_value *newParams, bool isSendable)
109 {
110     napi_status status;
111     bool isArray = false;
112     uint32_t len = 0;
113     napi_value length = nullptr;
114     napi_valuetype paramsType = napi_undefined;
115     if (napi_typeof(env, params, &paramsType) != napi_ok) {
116         RESMGR_HILOGE(RESMGR_JS_TAG, "Failed to get resource params property type");
117         return false;
118     }
119     if (paramsType == napi_undefined) {
120         return true;
121     }
122     if (napi_is_array(env, params, &isArray) != napi_ok || !isArray ||
123         napi_get_named_property(env, params, "length", &length) != napi_ok ||
124         napi_get_value_uint32(env, length, &len) != napi_ok) {
125         RESMGR_HILOGE(RESMGR_JS_TAG, "Resource params property params is error");
126         return false;
127     }
128     if (isSendable) {
129         status = napi_create_sendable_array_with_length(env, len, newParams);
130     } else {
131         status = napi_create_array_with_length(env, len, newParams);
132     }
133     if (status != napi_ok) {
134         RESMGR_HILOGE(RESMGR_JS_TAG, "Failed to create array, status = %{public}d", status);
135         return false;
136     }
137     napi_value jsValue = nullptr;
138     for (uint32_t i = 0; i < len; i++) {
139         if (napi_get_element(env, params, i, &jsValue) != napi_ok) {
140             RESMGR_HILOGE(RESMGR_JS_TAG, "Failed to get element");
141             return false;
142         }
143         if (napi_set_element(env, *(newParams), i, jsValue) != napi_ok) {
144             RESMGR_HILOGE(RESMGR_JS_TAG, "Failed to set element");
145             return false;
146         }
147     }
148     return true;
149 }
150 
InstanceResource(napi_env env,napi_callback_info info,bool isSendable)151 static napi_value InstanceResource(napi_env env, napi_callback_info info, bool isSendable)
152 {
153     std::vector<napi_value> props;
154     if (!GetResourceProp(env, info, props)) {
155         return nullptr;
156     }
157     napi_property_descriptor creatorProp[5] = { // array len
158         DECLARE_NAPI_DEFAULT_PROPERTY("bundleName", props[0]),
159         DECLARE_NAPI_DEFAULT_PROPERTY("moduleName", props[1]),
160         DECLARE_NAPI_DEFAULT_PROPERTY("id", props[2]),
161         DECLARE_NAPI_INSTANCE_GENERIC_PROPERTY("params"),
162         DECLARE_NAPI_INSTANCE_GENERIC_PROPERTY("type"),
163     };
164 
165     napi_value params = props[3]; // index 3
166     napi_value newParams = nullptr;
167     if (!GetParams(env, params, &newParams, isSendable)) {
168         return nullptr;
169     }
170     if (newParams != nullptr) {
171         creatorProp[3] = DECLARE_NAPI_DEFAULT_PROPERTY("params", newParams); // index 3
172     }
173 
174     napi_value type = props[4]; // index 4
175     napi_valuetype valueType = napi_undefined;
176     if (napi_typeof(env, type, &valueType) != napi_ok) {
177         RESMGR_HILOGE(RESMGR_JS_TAG, "Resource type property type is error");
178         return nullptr;
179     }
180     if (valueType != napi_undefined) {
181         if (valueType != napi_number) {
182             RESMGR_HILOGE(RESMGR_JS_TAG, "Resource type property type is not number");
183             return nullptr;
184         }
185         creatorProp[4] = DECLARE_NAPI_DEFAULT_PROPERTY("type", type); // index 4
186     }
187 
188     napi_value result = nullptr;
189     napi_status status;
190     if (isSendable) {
191         status = napi_create_sendable_object_with_properties(env, sizeof(creatorProp) / sizeof(creatorProp[0]),
192             creatorProp, &result);
193     } else {
194         status =napi_create_object_with_properties(env, &result, sizeof(creatorProp) / sizeof(creatorProp[0]),
195             creatorProp);
196     }
197     if (status != napi_ok) {
198         RESMGR_HILOGE(RESMGR_JS_TAG, "Failed to create object with properties, status = %{public}d", status);
199         return nullptr;
200     }
201     return result;
202 }
203 
ResourceToSendableResource(napi_env env,napi_callback_info info)204 static napi_value ResourceToSendableResource(napi_env env, napi_callback_info info)
205 {
206     napi_value result = InstanceResource(env, info, true);
207     if (result == nullptr) {
208         NapiThrow(env, ERROR_CODE_INVALID_INPUT_PARAMETER);
209         return nullptr;
210     }
211     return result;
212 }
213 
SendableResourceToResource(napi_env env,napi_callback_info info)214 static napi_value SendableResourceToResource(napi_env env, napi_callback_info info)
215 {
216     napi_value result = InstanceResource(env, info, false);
217     if (result == nullptr) {
218         NapiThrow(env, ERROR_CODE_INVALID_INPUT_PARAMETER);
219         return nullptr;
220     }
221     return result;
222 }
223 
SendableResourceManagerInit(napi_env env,napi_value exports)224 static napi_value SendableResourceManagerInit(napi_env env, napi_value exports)
225 {
226     napi_property_descriptor functionProp[] = {
227         DECLARE_NAPI_FUNCTION("resourceToSendableResource", ResourceToSendableResource),
228         DECLARE_NAPI_FUNCTION("sendableResourceToResource", SendableResourceToResource),
229     };
230 
231     napi_status status = napi_define_properties(env, exports, sizeof(functionProp) / sizeof(functionProp[0]),
232         functionProp);
233     if (status != napi_ok) {
234         RESMGR_HILOGE(RESMGR_JS_TAG, "Failed to set function at init");
235         return nullptr;
236     }
237 
238     return exports;
239 }
240 
241 static napi_module g_sendableResourceManagerModule = {
242     .nm_version = 1,
243     .nm_flags = 0,
244     .nm_filename = nullptr,
245     .nm_register_func = SendableResourceManagerInit,
246     .nm_modname = "sendableResourceManager",
247     .nm_priv = ((void*)0),
248     .reserved = {0}
249 };
250 
ResMgrRegister()251 extern "C" __attribute__((constructor)) void ResMgrRegister()
252 {
253     napi_module_register(&g_sendableResourceManagerModule);
254 }
255 } // namespace Resource
256 } // namespace Global
257 } // namespace OHOS