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 * value,const long size)59 void WebviewCreatePDFExecuteCallback::OnReceiveValue(const char* value, const long size)
60 {
61 if (value == nullptr || size <= 0) {
62 WVLOG_E("[CreatePDF] value is null or size is invalid");
63 return;
64 }
65 uv_loop_s* loop = nullptr;
66 uv_work_t* work = nullptr;
67
68 napi_get_uv_event_loop(env_, &loop);
69 if (loop == nullptr) {
70 return;
71 }
72 work = new (std::nothrow) uv_work_t;
73 if (work == nullptr) {
74 return;
75 }
76
77 ArrayBufferExecuteParam* param = new (std::nothrow) ArrayBufferExecuteParam();
78 if (param == nullptr) {
79 delete work;
80 return;
81 }
82 param->env_ = env_;
83 param->callbackRef_ = callbackRef_;
84 param->deferred_ = deferred_;
85 param->result_ = new (std::nothrow) char[size + 1];
86 if (param->result_ == nullptr) {
87 WVLOG_E("new char failed");
88 ReleaseArrayBufferExecuteParamAndUvWork(param, work);
89 return;
90 }
91 if (memcpy_s(param->result_, size, value, size) != 0) {
92 WVLOG_E("[CreatePDF] memcpy failed");
93 ReleaseArrayBufferExecuteParamAndUvWork(param, work);
94 return;
95 }
96 param->size_ = size;
97
98 work->data = reinterpret_cast<void*>(param);
99
100 int ret = uv_queue_work_with_qos(
101 loop, work, [](uv_work_t* work) {}, UvAfterWorkCb, uv_qos_user_initiated);
102 if (ret != 0) {
103 WVLOG_E("[CreatePDF] queue work failed");
104 ReleaseArrayBufferExecuteParamAndUvWork(param, work);
105 }
106 }
107
UvAfterWorkCb(uv_work_t * work,int status)108 void WebviewCreatePDFExecuteCallback::UvAfterWorkCb(uv_work_t* work, int status)
109 {
110 (void)status;
111 if (!work) {
112 return;
113 }
114 ArrayBufferExecuteParam* param = reinterpret_cast<ArrayBufferExecuteParam*>(work->data);
115 if (!param) {
116 WVLOG_E("[CreatePDF] param is null");
117 ReleaseArrayBufferExecuteParamAndUvWork(param, work);
118 return;
119 }
120 napi_handle_scope scope = nullptr;
121 napi_open_handle_scope(param->env_, &scope);
122 if (scope == nullptr) {
123 WVLOG_E("[CreatePDF] scope is null");
124 ReleaseArrayBufferExecuteParamAndUvWork(param, work);
125 return;
126 }
127 if (param->callbackRef_) {
128 UvAfterWorkCbAsync(param->env_, param->callbackRef_, param->result_, param->size_);
129 } else if (param->deferred_) {
130 UvAfterWorkCbPromise(param->env_, param->deferred_, param->result_, param->size_);
131 }
132
133 napi_close_handle_scope(param->env_, scope);
134 ReleaseArrayBufferExecuteParamAndUvWork(param, work);
135 }
136
UvAfterWorkCbAsync(napi_env env,napi_ref callbackRef,const char * result,const long size)137 void WebviewCreatePDFExecuteCallback::UvAfterWorkCbAsync(
138 napi_env env, napi_ref callbackRef, const char* result, const long size)
139 {
140 napi_value setResult[INTEGER_TWO] = { 0 };
141
142 if (result == nullptr) {
143 setResult[INTEGER_ZERO] = BusinessError::CreateError(env, NWebError::INVALID_RESOURCE);
144 napi_get_null(env, &setResult[INTEGER_ONE]);
145 } else {
146 napi_get_undefined(env, &setResult[INTEGER_ZERO]);
147 napi_value jsArrExt = nullptr;
148 NAPI_CALL_RETURN_VOID(env, napi_get_reference_value(env, g_jsArrExtClassRef, &jsArrExt));
149 NAPI_CALL_RETURN_VOID(env, napi_new_instance(env, jsArrExt, 0, NULL, &setResult[INTEGER_ONE]));
150
151 WebJsArrayBufferExt* webArrayBufferExt = new (std::nothrow) WebJsArrayBufferExt(result, size);
152 if (webArrayBufferExt == nullptr) {
153 WVLOG_E("new WebJsArrayBufferExt failed.");
154 return;
155 }
156
157 napi_status status = napi_wrap(
158 env, setResult[INTEGER_ONE], webArrayBufferExt,
159 [](napi_env env, void* data, void* hint) {
160 WebJsArrayBufferExt* webArrayBufferExt = static_cast<WebJsArrayBufferExt*>(data);
161 delete webArrayBufferExt;
162 webArrayBufferExt = nullptr;
163 },
164 nullptr, nullptr);
165 if (status != napi_status::napi_ok) {
166 if (webArrayBufferExt) {
167 delete webArrayBufferExt;
168 webArrayBufferExt = nullptr;
169 }
170 WVLOG_E("napi_wrap failed");
171 return;
172 }
173 }
174 napi_value args[INTEGER_TWO] = { setResult[INTEGER_ZERO], setResult[INTEGER_ONE] };
175 napi_value callback = nullptr;
176 napi_value callbackResult = nullptr;
177
178 napi_get_reference_value(env, callbackRef, &callback);
179 napi_call_function(env, nullptr, callback, INTEGER_TWO, args, &callbackResult);
180 napi_delete_reference(env, callbackRef);
181 }
182
UvAfterWorkCbPromise(napi_env env,napi_deferred deferred,const char * result,const long size)183 void WebviewCreatePDFExecuteCallback::UvAfterWorkCbPromise(
184 napi_env env, napi_deferred deferred, const char* result, const long size)
185 {
186 napi_value setResult[INTEGER_TWO] = { 0 };
187 setResult[INTEGER_ZERO] = NWebError::BusinessError::CreateError(env, NWebError::INVALID_RESOURCE);
188
189 napi_value jsArrExt = nullptr;
190 napi_status status = napi_get_reference_value(env, g_jsArrExtClassRef, &jsArrExt);
191 if (status != napi_status::napi_ok) {
192 WVLOG_E("napi_get_reference_value failed.");
193 return;
194 }
195 status = napi_new_instance(env, jsArrExt, 0, NULL, &setResult[INTEGER_ONE]);
196 if (status != napi_status::napi_ok) {
197 WVLOG_E("napi_new_instance failed.");
198 return;
199 }
200 WebJsArrayBufferExt* webArrayBufferExt = new (std::nothrow) WebJsArrayBufferExt(result, size);
201 if (webArrayBufferExt == nullptr) {
202 WVLOG_E("new WebJsArrayBufferExt failed.");
203 return;
204 }
205
206 status = napi_wrap(
207 env, setResult[INTEGER_ONE], webArrayBufferExt,
208 [](napi_env env, void* data, void* hint) {
209 WebJsArrayBufferExt* webArrayBufferExt = static_cast<WebJsArrayBufferExt*>(data);
210 delete webArrayBufferExt;
211 webArrayBufferExt = nullptr;
212 },
213 nullptr, nullptr);
214 if (status != napi_status::napi_ok) {
215 if (webArrayBufferExt) {
216 delete webArrayBufferExt;
217 webArrayBufferExt = nullptr;
218 }
219 WVLOG_E("napi_wrap failed.");
220 return;
221 }
222
223 napi_value args[INTEGER_TWO] = { setResult[INTEGER_ZERO], setResult[INTEGER_ONE] };
224 if (result == nullptr) {
225 napi_reject_deferred(env, deferred, args[INTEGER_ZERO]);
226 } else {
227 napi_resolve_deferred(env, deferred, args[INTEGER_ONE]);
228 }
229 }
230
JsConstructor(napi_env env,napi_callback_info info)231 napi_value NapiArrayBufferExt::JsConstructor(napi_env env, napi_callback_info info)
232 {
233 napi_value thisVar = nullptr;
234 napi_get_cb_info(env, info, nullptr, nullptr, &thisVar, nullptr);
235 return thisVar;
236 }
237
GetArrayBuffer(napi_env env,napi_callback_info info)238 napi_value NapiArrayBufferExt::GetArrayBuffer(napi_env env, napi_callback_info info)
239 {
240 napi_value thisVar = nullptr;
241 napi_value result = nullptr;
242 size_t argc = INTEGER_ONE;
243 napi_value argv[INTEGER_ONE] = { 0 };
244
245 WebJsArrayBufferExt* webArrayBufferExt = nullptr;
246 NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, &thisVar, nullptr));
247 NAPI_CALL(env, napi_unwrap(env, thisVar, (void**)&webArrayBufferExt));
248 if (webArrayBufferExt == nullptr) {
249 WVLOG_E("unwrap webArrayBufferExt failed.");
250 return result;
251 }
252
253 const char* pdfResult = webArrayBufferExt->GetPDFResult();
254 const long size = webArrayBufferExt->GetPDFSize();
255 if (pdfResult == nullptr || size <= 0) {
256 WVLOG_E("[CreatePDF] invalid PDF result or size");
257 return nullptr;
258 }
259 napi_value arraybuffer = nullptr;
260 void* bufferData = nullptr;
261
262 napi_status status = napi_create_arraybuffer(env, size, &bufferData, &arraybuffer);
263 if (status != napi_ok) {
264 WVLOG_E("[CreatePDF] create array buffer failed, status: %{public}d", status);
265 return nullptr;
266 }
267 if (bufferData == nullptr) {
268 WVLOG_E("[CreatePDF] bufferData is null after array buffer creation");
269 return nullptr;
270 }
271 if (memcpy_s(bufferData, size, pdfResult, size) != 0) {
272 WVLOG_E("[CreatePDF] memcpy failed");
273 return nullptr;
274 }
275 status = napi_create_typedarray(env, napi_typedarray_type::napi_uint8_array, size, arraybuffer, 0, &result);
276 if (status != napi_ok) {
277 WVLOG_E("[CreatePDF] create typed array failed, status: %{public}d", status);
278 return nullptr;
279 }
280 return result;
281 }
282
283 } // namespace OHOS::NWeb
284