1 /*
2  * Copyright (c) 2024-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 
16 #ifndef CAMERA_NAPI_OBJECT_H
17 #define CAMERA_NAPI_OBJECT_H
18 
19 #include <cstddef>
20 #include <cstdint>
21 #include <list>
22 #include <string>
23 #include <unordered_map>
24 #include <unordered_set>
25 #include <variant>
26 #include <vector>
27 
28 #include "js_native_api.h"
29 #include "js_native_api_types.h"
30 #include "napi/native_api.h"
31 
32 namespace OHOS {
33 namespace CameraStandard {
34 struct CameraNapiObject {
35 public:
36     typedef std::variant<bool*, int32_t*, uint32_t*, int64_t*, float*, double*, std::string*, CameraNapiObject*,
37         napi_value, std::vector<int32_t>*, std::list<CameraNapiObject>*>
38         NapiVariantBindAddr;
39 
40     typedef std::unordered_map<std::string, NapiVariantBindAddr> CameraNapiObjFieldMap;
41 
CameraNapiObjectCameraNapiObject42     CameraNapiObject(CameraNapiObjFieldMap fieldMap) : fieldMap_(fieldMap) {}
43 
ParseNapiObjectToMapCameraNapiObject44     napi_status ParseNapiObjectToMap(napi_env env, napi_value napiObject)
45     {
46         napi_valuetype type = napi_undefined;
47         napi_typeof(env, napiObject, &type);
48         if (type != napi_object) {
49             return napi_invalid_arg;
50         }
51         for (auto& it : fieldMap_) {
52             NapiVariantBindAddr& bindAddr = it.second;
53             napi_value napiObjValue = nullptr;
54             napi_status res = napi_get_named_property(env, napiObject, it.first.c_str(), &napiObjValue);
55             if (res != napi_ok) {
56                 return res;
57             }
58             napi_valuetype valueType = napi_undefined;
59             napi_typeof(env, napiObjValue, &valueType);
60             if (valueType == napi_undefined && optionalKeys_.find(it.first) != optionalKeys_.end()) {
61                 continue;
62             }
63             if (std::holds_alternative<bool*>(bindAddr)) {
64                 res = GetVariantBoolFromNapiValue(env, napiObjValue, bindAddr);
65             } else if (std::holds_alternative<int32_t*>(bindAddr)) {
66                 res = GetVariantInt32FromNapiValue(env, napiObjValue, bindAddr);
67             } else if (std::holds_alternative<uint32_t*>(bindAddr)) {
68                 res = GetVariantUint32FromNapiValue(env, napiObjValue, bindAddr);
69             } else if (std::holds_alternative<int64_t*>(bindAddr)) {
70                 res = GetVariantInt64FromNapiValue(env, napiObjValue, bindAddr);
71             } else if (std::holds_alternative<float*>(bindAddr)) {
72                 res = GetVariantFloatFromNapiValue(env, napiObjValue, bindAddr);
73             } else if (std::holds_alternative<double*>(bindAddr)) {
74                 res = GetVariantDoubleFromNapiValue(env, napiObjValue, bindAddr);
75             } else if (std::holds_alternative<std::string*>(bindAddr)) {
76                 res = GetVariantStringFromNapiValue(env, napiObjValue, bindAddr);
77             } else if (std::holds_alternative<CameraNapiObject*>(bindAddr)) {
78                 res = GetVariantCameraNapiObjectFromNapiValue(env, napiObjValue, bindAddr);
79             } else {
80                 res = napi_invalid_arg;
81             }
82             if (res != napi_ok) {
83                 return res;
84             }
85             settedKeys_.emplace(it.first);
86         }
87         return napi_ok;
88     };
89 
SetOptionalKeysCameraNapiObject90     void SetOptionalKeys(std::unordered_set<std::string>& keys)
91     {
92         optionalKeys_ = keys;
93     }
94 
IsKeySettedCameraNapiObject95     bool IsKeySetted(const std::string& key)
96     {
97         return settedKeys_.find(key) != settedKeys_.end();
98     }
99 
CreateNapiObjFromMapCameraNapiObject100     napi_value CreateNapiObjFromMap(napi_env env)
101     {
102         napi_value result = nullptr;
103         if (fieldMap_.empty()) {
104             napi_get_undefined(env, &result);
105             return result;
106         }
107         napi_create_object(env, &result);
108         for (auto& it : fieldMap_) {
109             NapiVariantBindAddr& bindAddr = it.second;
110             napi_value fieldValue = std::visit(CreateNapiObjVisitor(env), bindAddr);
111             napi_set_named_property(env, result, it.first.c_str(), fieldValue);
112         }
113         return result;
114     }
115 
116 private:
117     class CreateNapiObjVisitor {
118     public:
CreateNapiObjVisitorCameraNapiObject119         explicit CreateNapiObjVisitor(napi_env& env) : env_(env) {}
operatorCameraNapiObject120         napi_value operator()(bool*& variantAddr)
121         {
122             napi_value result = nullptr;
123             napi_status status = napi_get_boolean(env_, *variantAddr, &result);
124             return status == napi_ok ? result : nullptr;
125         }
operatorCameraNapiObject126         napi_value operator()(int32_t*& variantAddr)
127         {
128             napi_value result = nullptr;
129             napi_status status = napi_create_int32(env_, *variantAddr, &result);
130             return status == napi_ok ? result : nullptr;
131         }
operatorCameraNapiObject132         napi_value operator()(uint32_t*& variantAddr)
133         {
134             napi_value result = nullptr;
135             napi_status status = napi_create_uint32(env_, *variantAddr, &result);
136             return status == napi_ok ? result : nullptr;
137         }
operatorCameraNapiObject138         napi_value operator()(int64_t*& variantAddr)
139         {
140             napi_value result = nullptr;
141             napi_status status = napi_create_int64(env_, *variantAddr, &result);
142             return status == napi_ok ? result : nullptr;
143         }
operatorCameraNapiObject144         napi_value operator()(float*& variantAddr)
145         {
146             napi_value result = nullptr;
147             napi_status status = napi_create_double(env_, *variantAddr, &result);
148             return status == napi_ok ? result : nullptr;
149         }
operatorCameraNapiObject150         napi_value operator()(double*& variantAddr)
151         {
152             napi_value result = nullptr;
153             napi_status status = napi_create_double(env_, *variantAddr, &result);
154             return status == napi_ok ? result : nullptr;
155         }
operatorCameraNapiObject156         napi_value operator()(std::string*& variantAddr)
157         {
158             napi_value result = nullptr;
159             napi_status status = napi_create_string_utf8(env_, variantAddr->c_str(), variantAddr->size(), &result);
160             return status == napi_ok ? result : nullptr;
161         }
operatorCameraNapiObject162         napi_value operator()(CameraNapiObject*& variantAddr)
163         {
164             return variantAddr->CreateNapiObjFromMap(env_);
165         }
operatorCameraNapiObject166         napi_value operator()(napi_value& variantAddr)
167         {
168             return variantAddr;
169         }
operatorCameraNapiObject170         napi_value operator()(std::vector<int32_t>*& variantAddr)
171         {
172             napi_value result = nullptr;
173             napi_status status = napi_create_array(env_, &result);
174             if (status != napi_ok) {
175                 return nullptr;
176             }
177             auto& nativeArray = *variantAddr;
178             for (size_t i = 0; i < nativeArray.size(); i++) {
179                 napi_value item = nullptr;
180                 napi_create_int32(env_, nativeArray[i], &item);
181                 if (napi_set_element(env_, result, i, item) != napi_ok) {
182                     return nullptr;
183                 }
184             }
185             return result;
186         }
operatorCameraNapiObject187         napi_value operator()(std::list<CameraNapiObject>*& variantAddr)
188         {
189             napi_value result = nullptr;
190             napi_status status = napi_create_array(env_, &result);
191             if (status != napi_ok) {
192                 return nullptr;
193             }
194             auto& nativeArray = *variantAddr;
195             size_t index = 0;
196             for (auto& obj : nativeArray) {
197                 if (napi_set_element(env_, result, index, obj.CreateNapiObjFromMap(env_)) != napi_ok) {
198                     return nullptr;
199                 }
200                 index++;
201             }
202             return result;
203         }
204 
205     private:
206         napi_env& env_;
207     };
208 
GetVariantBoolFromNapiValueCameraNapiObject209     napi_status GetVariantBoolFromNapiValue(napi_env env, napi_value napiValue, NapiVariantBindAddr& variantAddr)
210     {
211         if (!ValidNapiType(env, napiValue, napi_boolean)) {
212             return napi_invalid_arg;
213         }
214         auto variantAddrPointer = std::get_if<bool*>(&variantAddr);
215         if (variantAddrPointer == nullptr) {
216             return napi_invalid_arg;
217         }
218         return napi_get_value_bool(env, napiValue, *variantAddrPointer);
219     };
220 
GetVariantInt32FromNapiValueCameraNapiObject221     napi_status GetVariantInt32FromNapiValue(napi_env env, napi_value napiValue, NapiVariantBindAddr& variantAddr)
222     {
223         if (!ValidNapiType(env, napiValue, napi_number)) {
224             return napi_invalid_arg;
225         }
226         auto variantAddrPointer = std::get_if<int32_t*>(&variantAddr);
227         if (variantAddrPointer == nullptr) {
228             return napi_invalid_arg;
229         }
230         return napi_get_value_int32(env, napiValue, *variantAddrPointer);
231     };
232 
GetVariantUint32FromNapiValueCameraNapiObject233     napi_status GetVariantUint32FromNapiValue(napi_env env, napi_value napiValue, NapiVariantBindAddr& variantAddr)
234     {
235         if (!ValidNapiType(env, napiValue, napi_number)) {
236             return napi_invalid_arg;
237         }
238         auto variantAddrPointer = std::get_if<uint32_t*>(&variantAddr);
239         if (variantAddrPointer == nullptr) {
240             return napi_invalid_arg;
241         }
242         return napi_get_value_uint32(env, napiValue, *variantAddrPointer);
243     };
244 
GetVariantInt64FromNapiValueCameraNapiObject245     napi_status GetVariantInt64FromNapiValue(napi_env env, napi_value napiValue, NapiVariantBindAddr& variantAddr)
246     {
247         if (!ValidNapiType(env, napiValue, napi_number)) {
248             return napi_invalid_arg;
249         }
250         auto variantAddrPointer = std::get_if<int64_t*>(&variantAddr);
251         if (variantAddrPointer == nullptr) {
252             return napi_invalid_arg;
253         }
254         return napi_get_value_int64(env, napiValue, *variantAddrPointer);
255     };
256 
GetVariantFloatFromNapiValueCameraNapiObject257     napi_status GetVariantFloatFromNapiValue(napi_env env, napi_value napiValue, NapiVariantBindAddr& variantAddr)
258     {
259         if (!ValidNapiType(env, napiValue, napi_number)) {
260             return napi_invalid_arg;
261         }
262         auto variantAddrPointer = std::get_if<float*>(&variantAddr);
263         if (variantAddrPointer == nullptr) {
264             return napi_invalid_arg;
265         }
266         double tmpData = 0;
267         napi_status res = napi_get_value_double(env, napiValue, &tmpData);
268         **variantAddrPointer = tmpData;
269         return res;
270     };
271 
GetVariantDoubleFromNapiValueCameraNapiObject272     napi_status GetVariantDoubleFromNapiValue(napi_env env, napi_value napiValue, NapiVariantBindAddr& variantAddr)
273     {
274         if (!ValidNapiType(env, napiValue, napi_number)) {
275             return napi_invalid_arg;
276         }
277         auto variantAddrPointer = std::get_if<double*>(&variantAddr);
278         if (variantAddrPointer == nullptr) {
279             return napi_invalid_arg;
280         }
281         return napi_get_value_double(env, napiValue, *variantAddrPointer);
282     };
283 
GetVariantStringFromNapiValueCameraNapiObject284     napi_status GetVariantStringFromNapiValue(napi_env env, napi_value napiValue, NapiVariantBindAddr& variantAddr)
285     {
286         if (!ValidNapiType(env, napiValue, napi_string)) {
287             return napi_invalid_arg;
288         }
289 
290         auto variantAddrPointer = std::get_if<std::string*>(&variantAddr);
291         if (variantAddrPointer == nullptr) {
292             return napi_invalid_arg;
293         }
294 
295         size_t stringSize = 0;
296         napi_status res = napi_get_value_string_utf8(env, napiValue, nullptr, 0, &stringSize);
297         if (res != napi_ok) {
298             return res;
299         }
300         auto& stringValue = **variantAddrPointer;
301         stringValue.resize(stringSize);
302         res = napi_get_value_string_utf8(env, napiValue, stringValue.data(), stringSize + 1, &stringSize);
303         return res;
304     };
305 
GetVariantCameraNapiObjectFromNapiValueCameraNapiObject306     napi_status GetVariantCameraNapiObjectFromNapiValue(
307         napi_env env, napi_value napiValue, NapiVariantBindAddr& variantAddr)
308     {
309         if (!ValidNapiType(env, napiValue, napi_object)) {
310             return napi_invalid_arg;
311         }
312         auto variantAddrPointer = std::get_if<CameraNapiObject*>(&variantAddr);
313         if (variantAddrPointer == nullptr) {
314             return napi_invalid_arg;
315         }
316         return (*variantAddrPointer)->ParseNapiObjectToMap(env, napiValue);
317     }
318 
ValidNapiTypeCameraNapiObject319     bool ValidNapiType(napi_env env, napi_value napiObjValue, napi_valuetype valueType)
320     {
321         napi_valuetype objValueType = napi_undefined;
322         napi_status res = napi_typeof(env, napiObjValue, &objValueType);
323         if (res != napi_ok) {
324             return false;
325         }
326         return objValueType == valueType;
327     }
328 
329     CameraNapiObjFieldMap fieldMap_;
330     std::unordered_set<std::string> optionalKeys_;
331     std::unordered_set<std::string> settedKeys_;
332 };
333 } // namespace CameraStandard
334 } // namespace OHOS
335 #endif /* CAMERA_NAPI_OBJECT_H */
336