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