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