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_PARAM_PARSER_H
17 #define CAMERA_NAPI_PARAM_PARSER_H
18 
19 #include <cmath>
20 #include <cstddef>
21 #include <cstdint>
22 #include <memory>
23 #include <set>
24 #include <stdint.h>
25 #include <string>
26 #include <unordered_map>
27 #include <unordered_set>
28 #include <utility>
29 #include <variant>
30 
31 #include "camera_error_code.h"
32 #include "camera_napi_const.h"
33 #include "camera_napi_object.h"
34 #include "js_native_api.h"
35 #include "js_native_api_types.h"
36 #include "napi/native_api.h"
37 
38 namespace OHOS {
39 namespace CameraStandard {
40 enum CameraNapiAsyncFunctionType : int32_t { ASYNC_FUN_TYPE_NONE, ASYNC_FUN_TYPE_CALLBACK, ASYNC_FUN_TYPE_PROMISE };
41 struct CameraNapiAsyncFunction {
42 public:
CameraNapiAsyncFunctionCameraNapiAsyncFunction43     CameraNapiAsyncFunction(napi_env env, const char* resourceName, napi_ref& callbackRef, napi_deferred& deferred)
44     {
45         env_ = env;
46         status_ = napi_create_string_utf8(env, resourceName, NAPI_AUTO_LENGTH, &(resourceName_));
47         if (status_ != napi_ok) {
48             return;
49         }
50         callbackRefPtr_ = &callbackRef;
51         deferred_ = &deferred;
52     }
53 
GetResourceNameCameraNapiAsyncFunction54     inline napi_value GetResourceName()
55     {
56         return resourceName_;
57     }
58 
IsStatusOkCameraNapiAsyncFunction59     inline bool IsStatusOk()
60     {
61         return status_ == napi_ok;
62     }
63 
GetPromiseCameraNapiAsyncFunction64     inline napi_value GetPromise()
65     {
66         if (status_ != napi_ok) {
67             return nullptr;
68         }
69         return promise_;
70     }
71 
GetAsyncFunctionTypeCameraNapiAsyncFunction72     inline CameraNapiAsyncFunctionType GetAsyncFunctionType()
73     {
74         return asyncFunctionType_;
75     }
76 
AssertStatusCameraNapiAsyncFunction77     inline bool AssertStatus(CameraErrorCode errorCode, const char* message)
78     {
79         if (status_ != napi_ok) {
80             napi_throw_error(env_, std::to_string(errorCode).c_str(), message);
81         }
82         return status_ == napi_ok;
83     }
84 
ResetCameraNapiAsyncFunction85     void Reset()
86     {
87         if (callbackRefPtr_ != nullptr && *callbackRefPtr_ != nullptr) {
88             napi_delete_reference(env_, *callbackRefPtr_);
89             *callbackRefPtr_ = nullptr;
90         }
91         if (deferred_ != nullptr && *deferred_ != nullptr) {
92             napi_value rejection = nullptr;
93             napi_get_undefined(env_, &rejection);
94             napi_reject_deferred(env_, *deferred_, rejection);
95             *deferred_ = nullptr;
96         }
97     }
98 
99 private:
CreatePromiseCameraNapiAsyncFunction100     napi_status CreatePromise()
101     {
102         if (status_ != napi_ok) {
103             return status_;
104         }
105         status_ = napi_create_promise(env_, deferred_, &promise_);
106         if (status_ == napi_ok) {
107             asyncFunctionType_ = ASYNC_FUN_TYPE_PROMISE;
108         }
109         return status_;
110     }
111 
CreateCallbackCameraNapiAsyncFunction112     inline napi_status CreateCallback(napi_value callback)
113     {
114         if (status_ != napi_ok) {
115             return status_;
116         }
117         status_ = napi_create_reference(env_, callback, 1, callbackRefPtr_);
118         if (status_ == napi_ok) {
119             asyncFunctionType_ = ASYNC_FUN_TYPE_CALLBACK;
120         }
121         return status_;
122     }
123 
124     napi_env env_ = nullptr;
125     napi_status status_ = napi_invalid_arg;
126     napi_value resourceName_ = nullptr;
127     napi_ref* callbackRefPtr_ = nullptr;
128     napi_deferred* deferred_ = nullptr;
129     napi_value promise_ = nullptr;
130     CameraNapiAsyncFunctionType asyncFunctionType_ = ASYNC_FUN_TYPE_NONE;
131 
132     friend class CameraNapiParamParser;
133 };
134 
135 class CameraNapiParamParser {
136 public:
137     template<typename T>
CameraNapiParamParser(napi_env env,napi_callback_info info,T * & nativeObjPointer)138     explicit CameraNapiParamParser(napi_env env, napi_callback_info info, T*& nativeObjPointer)
139         : CameraNapiParamParser(env, info, 0, nativeObjPointer, nullptr)
140     {}
141 
142     template<typename T>
CameraNapiParamParser(napi_env env,napi_callback_info info,T * & nativeObjPointer,std::shared_ptr<CameraNapiAsyncFunction> asyncFunction)143     explicit CameraNapiParamParser(napi_env env, napi_callback_info info, T*& nativeObjPointer,
144         std::shared_ptr<CameraNapiAsyncFunction> asyncFunction)
145         : CameraNapiParamParser(env, info, 0, nativeObjPointer, asyncFunction)
146     {}
147 
148     template<typename T, typename... Args>
CameraNapiParamParser(napi_env env,napi_callback_info info,T * & nativeObjPointer,Args &...args)149     explicit CameraNapiParamParser(napi_env env, napi_callback_info info, T*& nativeObjPointer, Args&... args)
150         : CameraNapiParamParser(env, info, sizeof...(args), nativeObjPointer, nullptr)
151     {
152         if (napiError != napi_ok) {
153             return;
154         }
155         if (paramSize_ > 0) {
156             Next(args...);
157         }
158     }
159 
160     template<typename T, typename... Args>
CameraNapiParamParser(napi_env env,napi_callback_info info,T * & nativeObjPointer,std::shared_ptr<CameraNapiAsyncFunction> asyncFunction,Args &...args)161     explicit CameraNapiParamParser(napi_env env, napi_callback_info info, T*& nativeObjPointer,
162         std::shared_ptr<CameraNapiAsyncFunction> asyncFunction, Args&... args)
163         : CameraNapiParamParser(env, info, sizeof...(args), nativeObjPointer, asyncFunction)
164     {
165         if (napiError != napi_ok) {
166             return;
167         }
168         if (paramSize_ > 0) {
169             Next(args...);
170         }
171     }
172 
173     template<typename... Args>
CameraNapiParamParser(napi_env env,std::vector<napi_value> paramValue,Args &...args)174     explicit CameraNapiParamParser(napi_env env, std::vector<napi_value> paramValue, Args&... args)
175         : env_(env), paramSize_(sizeof...(args)), paramValue_(paramValue)
176     {
177         if (paramSize_ != paramValue_.size()) {
178             napiError = napi_status::napi_invalid_arg;
179             return;
180         }
181         napiError = napi_ok;
182         if (paramSize_ > 0) {
183             Next(args...);
184         }
185     }
186 
AssertStatus(CameraErrorCode errorCode,const char * message)187     inline bool AssertStatus(CameraErrorCode errorCode, const char* message)
188     {
189         if (napiError != napi_ok) {
190             napi_throw_error(env_, std::to_string(errorCode).c_str(), message);
191         }
192         return napiError == napi_ok;
193     }
194 
IsStatusOk()195     inline bool IsStatusOk()
196     {
197         return napiError == napi_ok;
198     }
199 
GetThisVar()200     inline napi_value GetThisVar()
201     {
202         return thisVar_;
203     }
204 
205 private:
206     template<typename T>
CameraNapiParamParser(napi_env env,napi_callback_info info,size_t napiParamSize,T * & nativeObjPointer,std::shared_ptr<CameraNapiAsyncFunction> asyncFunction)207     explicit CameraNapiParamParser(napi_env env, napi_callback_info info, size_t napiParamSize, T*& nativeObjPointer,
208         std::shared_ptr<CameraNapiAsyncFunction> asyncFunction)
209         : env_(env), asyncFunction_(asyncFunction)
210     {
211         size_t paramSizeIncludeAsyncFun = napiParamSize + (asyncFunction_ == nullptr ? 0 : 1);
212         paramSize_ = paramSizeIncludeAsyncFun;
213         paramValue_.resize(paramSize_, nullptr);
214         napiError = napi_get_cb_info(env_, info, &paramSize_, paramValue_.data(), &thisVar_, nullptr);
215         if (napiError != napi_ok) {
216             return;
217         }
218         if (asyncFunction_ != nullptr) {
219             asyncFunction->Reset();
220             // Check callback function
221             if (paramSize_ > 0 && paramSize_ == paramSizeIncludeAsyncFun) {
222                 napi_valuetype napiType = napi_undefined;
223                 napi_typeof(env, paramValue_[paramSize_ - 1], &napiType);
224                 if (napiType == napi_function) {
225                     napiError = asyncFunction_->CreateCallback(paramValue_[paramSize_ - 1]);
226                 } else {
227                     napiError = napi_status::napi_invalid_arg;
228                 }
229             } else if (paramSizeIncludeAsyncFun > 0 && paramSize_ == paramSizeIncludeAsyncFun - 1) {
230                 napiError = asyncFunction_->CreatePromise();
231             } else {
232                 napiError = napi_status::napi_invalid_arg;
233             }
234             if (napiError != napi_ok) {
235                 return;
236             }
237         } else if (paramSize_ != napiParamSize) {
238             napiError = napi_status::napi_invalid_arg;
239             return;
240         }
241         UnwrapThisVarToAddr(thisVar_, nativeObjPointer);
242     }
243 
244     template<typename T>
UnwrapThisVarToAddr(napi_value thisVar,T * & dataPointAddr)245     void UnwrapThisVarToAddr(napi_value thisVar, T*& dataPointAddr)
246     {
247         if (napiError != napi_ok) {
248             return;
249         }
250         if (thisVar == nullptr) {
251             napiError = napi_invalid_arg;
252             return;
253         }
254         napiError = napi_unwrap(env_, thisVar, reinterpret_cast<void**>(&dataPointAddr));
255         if (napiError == napi_ok && dataPointAddr == nullptr) {
256             napiError = napi_invalid_arg;
257         }
258     }
259 
Next(CameraNapiObject & cameraNapiOjbect)260     CameraNapiParamParser& Next(CameraNapiObject& cameraNapiOjbect)
261     {
262         if (napiError != napi_status::napi_ok) {
263             return *this;
264         }
265         if (paraIndex_ >= paramSize_) {
266             napiError = napi_status::napi_invalid_arg;
267             return *this;
268         }
269         napiError = cameraNapiOjbect.ParseNapiObjectToMap(env_, paramValue_[paraIndex_]);
270         paraIndex_++;
271         return *this;
272     }
273 
274     template<typename T>
Next(T * & outData)275     CameraNapiParamParser& Next(T*& outData)
276     {
277         if (napiError != napi_status::napi_ok) {
278             return *this;
279         }
280         if (paraIndex_ >= paramSize_) {
281             napiError = napi_status::napi_invalid_arg;
282             return *this;
283         }
284         napi_valuetype valueNapiType = napi_undefined;
285         napi_typeof(env_, paramValue_[paraIndex_], &valueNapiType);
286         if (valueNapiType == napi_object) {
287             napiError = napi_unwrap(env_, paramValue_[paraIndex_], reinterpret_cast<void**>(&outData));
288             if (napiError == napi_ok && outData == nullptr) {
289                 napiError = napi_invalid_arg;
290             }
291         } else {
292             napiError = napi_status::napi_invalid_arg;
293         }
294         paraIndex_++;
295         return *this;
296     }
297 
298     template<typename T, typename = std::enable_if_t<std::is_same_v<T, bool> || std::is_same_v<T, int32_t> ||
299                                                      std::is_same_v<T, int64_t> || std::is_same_v<T, uint32_t> ||
300                                                      std::is_same_v<T, double> || std::is_same_v<T, std::string>>>
Next(T & outData)301     CameraNapiParamParser& Next(T& outData)
302     {
303         if (napiError != napi_status::napi_ok) {
304             return *this;
305         }
306         if (paraIndex_ >= paramSize_) {
307             napiError = napi_status::napi_invalid_arg;
308             return *this;
309         }
310         napi_valuetype valueNapiType = napi_undefined;
311         napi_typeof(env_, paramValue_[paraIndex_], &valueNapiType);
312         if (std::is_same_v<T, bool> && valueNapiType == napi_boolean) {
313             napiError = napi_get_value_bool(env_, paramValue_[paraIndex_], (bool*)(&outData));
314         } else if (std::is_same_v<T, int32_t> && valueNapiType == napi_number) {
315             napiError = napi_get_value_int32(env_, paramValue_[paraIndex_], (int32_t*)(&outData));
316         } else if (std::is_same_v<T, int64_t> && valueNapiType == napi_number) {
317             napiError = napi_get_value_int64(env_, paramValue_[paraIndex_], (int64_t*)(&outData));
318         } else if (std::is_same_v<T, uint32_t> && valueNapiType == napi_number) {
319             napiError = napi_get_value_uint32(env_, paramValue_[paraIndex_], (uint32_t*)(&outData));
320         } else if (std::is_same_v<T, double> && valueNapiType == napi_number) {
321             napiError = napi_get_value_double(env_, paramValue_[paraIndex_], (double*)(&outData));
322         } else if (std::is_same_v<T, std::string> && valueNapiType == napi_string) {
323             size_t stringSize = 0;
324             napiError = napi_get_value_string_utf8(env_, paramValue_[paraIndex_], nullptr, 0, &stringSize);
325             if (napiError != napi_ok) {
326                 paraIndex_++;
327                 return *this;
328             }
329             std::string* stringPtr = (std::string*)(&outData);
330             stringPtr->resize(stringSize);
331             napiError = napi_get_value_string_utf8(
332                 env_, paramValue_[paraIndex_], stringPtr->data(), stringSize + 1, &stringSize);
333             if (napiError != napi_ok) {
334                 paraIndex_++;
335                 return *this;
336             }
337         } else {
338             napiError = napi_status::napi_invalid_arg;
339         }
340         paraIndex_++;
341         return *this;
342     }
343 
344     template<typename T, typename... Args>
Next(T & outData,Args &...args)345     CameraNapiParamParser& Next(T& outData, Args&... args)
346     {
347         Next(outData);
348         if (sizeof...(args) > 0) {
349             Next(args...);
350         }
351         return *this;
352     }
353 
354     napi_env env_ = nullptr;
355     napi_value thisVar_ = nullptr;
356     size_t paramSize_ = 0;
357 
358     size_t paraIndex_ = 0;
359     std::vector<napi_value> paramValue_ {};
360     std::shared_ptr<CameraNapiAsyncFunction> asyncFunction_ = nullptr;
361     napi_status napiError = napi_status::napi_invalid_arg;
362 };
363 } // namespace CameraStandard
364 } // namespace OHOS
365 #endif