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 
16 #include <fstream>
17 #include <iostream>
18 #include <securec.h>
19 
20 #include "business_error.h"
21 #include "napi_parse_utils.h"
22 #include "nweb_log.h"
23 #include "web_errors.h"
24 #include "webview_createpdf_execute_callback.h"
25 namespace OHOS::NWeb {
26 using namespace NWebError;
27 const std::string JS_EXT_ARR_CLASS_NAME = "PdfData";
28 thread_local napi_ref g_jsArrExtClassRef;
29 // static
InitJSExcute(napi_env env, napi_value exports)30 void WebviewCreatePDFExecuteCallback::InitJSExcute(napi_env env, napi_value exports)
31 {
32     napi_value jsArrExtClass = nullptr;
33     napi_property_descriptor jsArrExtClsProperties[] = { DECLARE_NAPI_FUNCTION(
34         "pdfArrayBuffer", NapiArrayBufferExt::GetArrayBuffer) };
35     napi_define_class(env, JS_EXT_ARR_CLASS_NAME.c_str(), JS_EXT_ARR_CLASS_NAME.length(),
36         NapiArrayBufferExt::JsConstructor, nullptr, sizeof(jsArrExtClsProperties) / sizeof(jsArrExtClsProperties[0]),
37         jsArrExtClsProperties, &jsArrExtClass);
38     napi_create_reference(env, jsArrExtClass, 1, &g_jsArrExtClassRef);
39     napi_set_named_property(env, exports, JS_EXT_ARR_CLASS_NAME.c_str(), jsArrExtClass);
40 }
41 
ReleaseArrayBufferExecuteParamAndUvWork( ArrayBufferExecuteParam* param, uv_work_t* work)42 void WebviewCreatePDFExecuteCallback::ReleaseArrayBufferExecuteParamAndUvWork(
43     ArrayBufferExecuteParam* param, uv_work_t* work)
44 {
45     if (param != nullptr) {
46         if (param->result_ != nullptr) {
47             delete param->result_;
48             param->result_ = nullptr;
49         }
50         delete param;
51         param = nullptr;
52     }
53     if (work != nullptr) {
54         delete work;
55         work = nullptr;
56     }
57 }
58 
OnReceiveValue(const char* result, const long size)59 void WebviewCreatePDFExecuteCallback::OnReceiveValue(const char* result, const long size)
60 {
61     uv_loop_s* loop = nullptr;
62     uv_work_t* work = nullptr;
63 
64     napi_get_uv_event_loop(env_, &loop);
65     if (loop == nullptr) {
66         return;
67     }
68     work = new (std::nothrow) uv_work_t;
69     if (work == nullptr) {
70         return;
71     }
72 
73     ArrayBufferExecuteParam* param = new (std::nothrow) ArrayBufferExecuteParam();
74     if (param == nullptr) {
75         delete work;
76         return;
77     }
78     param->env_ = env_;
79     param->callbackRef_ = callbackRef_;
80     param->deferred_ = deferred_;
81     param->result_ = new (std::nothrow) char[size + 1];
82     if(param->result_ == nullptr){
83         WVLOG_E("new char failed");
84         ReleaseArrayBufferExecuteParamAndUvWork(param, work);
85         return;
86     }
87     if (memcpy_s(param->result_, size, result, size) != 0) {
88         WVLOG_E("[CreatePDF] memcpy failed");
89         ReleaseArrayBufferExecuteParamAndUvWork(param, work);
90         return;
91     }
92     param->size_ = size;
93 
94     work->data = reinterpret_cast<void*>(param);
95 
96     int ret = uv_queue_work_with_qos(
97         loop, work, [](uv_work_t* work) {}, UvAfterWorkCb, uv_qos_user_initiated);
98     if (ret != 0) {
99         WVLOG_E("[CreatePDF] queue work failed");
100         ReleaseArrayBufferExecuteParamAndUvWork(param, work);
101     }
102 }
103 
UvAfterWorkCb(uv_work_t* work, int status)104 void WebviewCreatePDFExecuteCallback::UvAfterWorkCb(uv_work_t* work, int status)
105 {
106     (void)status;
107     if (!work) {
108         return;
109     }
110     ArrayBufferExecuteParam* param = reinterpret_cast<ArrayBufferExecuteParam*>(work->data);
111     if (!param) {
112         WVLOG_E("[CreatePDF] param is null");
113         ReleaseArrayBufferExecuteParamAndUvWork(param, work);
114         return;
115     }
116     napi_handle_scope scope = nullptr;
117     napi_open_handle_scope(param->env_, &scope);
118     if (scope == nullptr) {
119         WVLOG_E("[CreatePDF] scope is null");
120         ReleaseArrayBufferExecuteParamAndUvWork(param, work);
121         return;
122     }
123     if (param->callbackRef_) {
124         UvAfterWorkCbAsync(param->env_, param->callbackRef_, param->result_, param->size_);
125     } else if (param->deferred_) {
126         UvAfterWorkCbPromise(param->env_, param->deferred_, param->result_, param->size_);
127     }
128 
129     napi_close_handle_scope(param->env_, scope);
130     ReleaseArrayBufferExecuteParamAndUvWork(param, work);
131 }
132 
UvAfterWorkCbAsync( napi_env env, napi_ref callbackRef, const char* result, const long size)133 void WebviewCreatePDFExecuteCallback::UvAfterWorkCbAsync(
134     napi_env env, napi_ref callbackRef, const char* result, const long size)
135 {
136     napi_value setResult[INTEGER_TWO] = { 0 };
137 
138     if (result == nullptr) {
139         setResult[INTEGER_ZERO] = BusinessError::CreateError(env, NWebError::INVALID_RESOURCE);
140         napi_get_null(env, &setResult[INTEGER_ONE]);
141     } else {
142         napi_get_undefined(env, &setResult[INTEGER_ZERO]);
143         napi_value jsArrExt = nullptr;
144         NAPI_CALL_RETURN_VOID(env, napi_get_reference_value(env, g_jsArrExtClassRef, &jsArrExt));
145         NAPI_CALL_RETURN_VOID(env, napi_new_instance(env, jsArrExt, 0, NULL, &setResult[INTEGER_ONE]));
146 
147         WebJsArrayBufferExt* webArrayBufferExt = new (std::nothrow) WebJsArrayBufferExt(result, size);
148         if (webArrayBufferExt == nullptr) {
149             WVLOG_E("new WebJsArrayBufferExt failed.");
150             return;
151         }
152 
153         napi_status status = napi_wrap(
154             env, setResult[INTEGER_ONE], webArrayBufferExt,
155             [](napi_env env, void* data, void* hint) {
156                 WebJsArrayBufferExt* webArrayBufferExt = static_cast<WebJsArrayBufferExt*>(data);
157                 delete webArrayBufferExt;
158                 webArrayBufferExt = nullptr;
159             },
160             nullptr, nullptr);
161         if (status != napi_status::napi_ok) {
162             WVLOG_E("napi_wrap failed");
163             return;
164         }
165     }
166     napi_value args[INTEGER_TWO] = { setResult[INTEGER_ZERO], setResult[INTEGER_ONE] };
167     napi_value callback = nullptr;
168     napi_value callbackResult = nullptr;
169 
170     napi_get_reference_value(env, callbackRef, &callback);
171     napi_call_function(env, nullptr, callback, INTEGER_TWO, args, &callbackResult);
172     napi_delete_reference(env, callbackRef);
173 }
174 
UvAfterWorkCbPromise( napi_env env, napi_deferred deferred, const char* result, const long size)175 void WebviewCreatePDFExecuteCallback::UvAfterWorkCbPromise(
176     napi_env env, napi_deferred deferred, const char* result, const long size)
177 {
178     napi_value setResult[INTEGER_TWO] = { 0 };
179     setResult[INTEGER_ZERO] = NWebError::BusinessError::CreateError(env, NWebError::INVALID_RESOURCE);
180 
181     napi_value jsArrExt = nullptr;
182     napi_status status = napi_get_reference_value(env, g_jsArrExtClassRef, &jsArrExt);
183     if (status != napi_status::napi_ok) {
184         WVLOG_E("napi_get_reference_value failed.");
185         return;
186     }
187     status = napi_new_instance(env, jsArrExt, 0, NULL, &setResult[INTEGER_ONE]);
188     if (status != napi_status::napi_ok) {
189         WVLOG_E("napi_new_instance failed.");
190         return;
191     }
192     WebJsArrayBufferExt* webArrayBufferExt = new (std::nothrow) WebJsArrayBufferExt(result, size);
193     if (webArrayBufferExt == nullptr) {
194         WVLOG_E("new WebJsArrayBufferExt failed.");
195         return;
196     }
197 
198     status = napi_wrap(
199         env, setResult[INTEGER_ONE], webArrayBufferExt,
200         [](napi_env env, void* data, void* hint) {
201             WebJsArrayBufferExt* webArrayBufferExt = static_cast<WebJsArrayBufferExt*>(data);
202             delete webArrayBufferExt;
203             webArrayBufferExt = nullptr;
204         },
205         nullptr, nullptr);
206     if (status != napi_status::napi_ok) {
207         WVLOG_E("napi_wrap failed.");
208         return;
209     }
210 
211     napi_value args[INTEGER_TWO] = { setResult[INTEGER_ZERO], setResult[INTEGER_ONE] };
212     if (result == nullptr) {
213         napi_reject_deferred(env, deferred, args[INTEGER_ZERO]);
214     } else {
215         napi_resolve_deferred(env, deferred, args[INTEGER_ONE]);
216     }
217 }
218 
JsConstructor(napi_env env, napi_callback_info info)219 napi_value NapiArrayBufferExt::JsConstructor(napi_env env, napi_callback_info info)
220 {
221     napi_value thisVar = nullptr;
222     napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
223     return thisVar;
224 }
225 
GetArrayBuffer(napi_env env, napi_callback_info info)226 napi_value NapiArrayBufferExt::GetArrayBuffer(napi_env env, napi_callback_info info)
227 {
228     napi_value thisVar = nullptr;
229     napi_value result = nullptr;
230     size_t argc = INTEGER_ONE;
231     napi_value argv[INTEGER_ONE] = { 0 };
232 
233     WebJsArrayBufferExt* webArrayBufferExt = nullptr;
234     NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
235     NAPI_CALL(env, napi_unwrap(env, thisVar, (void**)&webArrayBufferExt));
236     if (webArrayBufferExt == nullptr) {
237         WVLOG_E("unwrap webArrayBufferExt failed.");
238         return result;
239     }
240 
241     const char* pdfResult = webArrayBufferExt->GetPDFResult();
242     const long size = webArrayBufferExt->GetPDFSize();
243     napi_value arraybuffer = nullptr;
244     void* bufferData = nullptr;
245 
246     napi_status status = napi_create_arraybuffer(env, size, &bufferData, &arraybuffer);
247     if (status != napi_ok) {
248         WVLOG_E("[CreatePDF] create array buffer failed, status: %{public}d", status);
249         return nullptr;
250     }
251     if (memcpy_s(bufferData, size, pdfResult, size) != 0) {
252         WVLOG_E("[CreatePDF] memcpy failed");
253         return nullptr;
254     }
255     status = napi_create_typedarray(env, napi_typedarray_type::napi_uint8_array, size, arraybuffer, 0, &result);
256     if (status != napi_ok) {
257         WVLOG_E("[CreatePDF] create typed array failed, status: %{public}d", status);
258         return nullptr;
259     }
260     napi_ref arraybufferRef;
261     napi_create_reference(env, arraybuffer, 1, &arraybufferRef);
262 
263     return result;
264 }
265 
266 } // namespace OHOS::NWeb
267