1 // Copyright 2020 The PDFium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com
6
7 #include "fxjs/fxv8.h"
8
9 #include "third_party/base/numerics/safe_conversions.h"
10 #include "v8/include/v8-container.h"
11 #include "v8/include/v8-date.h"
12 #include "v8/include/v8-exception.h"
13 #include "v8/include/v8-isolate.h"
14 #include "v8/include/v8-primitive.h"
15 #include "v8/include/v8-value.h"
16
17 namespace fxv8 {
18
IsUndefined(v8::Local<v8::Value> value)19 bool IsUndefined(v8::Local<v8::Value> value) {
20 return !value.IsEmpty() && value->IsUndefined();
21 }
22
IsNull(v8::Local<v8::Value> value)23 bool IsNull(v8::Local<v8::Value> value) {
24 return !value.IsEmpty() && value->IsNull();
25 }
26
IsBoolean(v8::Local<v8::Value> value)27 bool IsBoolean(v8::Local<v8::Value> value) {
28 return !value.IsEmpty() && value->IsBoolean();
29 }
30
IsString(v8::Local<v8::Value> value)31 bool IsString(v8::Local<v8::Value> value) {
32 return !value.IsEmpty() && value->IsString();
33 }
34
IsNumber(v8::Local<v8::Value> value)35 bool IsNumber(v8::Local<v8::Value> value) {
36 return !value.IsEmpty() && value->IsNumber();
37 }
38
IsInteger(v8::Local<v8::Value> value)39 bool IsInteger(v8::Local<v8::Value> value) {
40 return !value.IsEmpty() && value->IsInt32();
41 }
42
IsObject(v8::Local<v8::Value> value)43 bool IsObject(v8::Local<v8::Value> value) {
44 return !value.IsEmpty() && value->IsObject();
45 }
46
IsArray(v8::Local<v8::Value> value)47 bool IsArray(v8::Local<v8::Value> value) {
48 return !value.IsEmpty() && value->IsArray();
49 }
50
IsDate(v8::Local<v8::Value> value)51 bool IsDate(v8::Local<v8::Value> value) {
52 return !value.IsEmpty() && value->IsDate();
53 }
54
IsFunction(v8::Local<v8::Value> value)55 bool IsFunction(v8::Local<v8::Value> value) {
56 return !value.IsEmpty() && value->IsFunction();
57 }
58
NewNullHelper(v8::Isolate * pIsolate)59 v8::Local<v8::Value> NewNullHelper(v8::Isolate* pIsolate) {
60 return v8::Null(pIsolate);
61 }
62
NewUndefinedHelper(v8::Isolate * pIsolate)63 v8::Local<v8::Value> NewUndefinedHelper(v8::Isolate* pIsolate) {
64 return v8::Undefined(pIsolate);
65 }
66
NewNumberHelper(v8::Isolate * pIsolate,int number)67 v8::Local<v8::Number> NewNumberHelper(v8::Isolate* pIsolate, int number) {
68 return v8::Int32::New(pIsolate, number);
69 }
70
NewNumberHelper(v8::Isolate * pIsolate,double number)71 v8::Local<v8::Number> NewNumberHelper(v8::Isolate* pIsolate, double number) {
72 return v8::Number::New(pIsolate, number);
73 }
74
NewNumberHelper(v8::Isolate * pIsolate,float number)75 v8::Local<v8::Number> NewNumberHelper(v8::Isolate* pIsolate, float number) {
76 return v8::Number::New(pIsolate, number);
77 }
78
NewBooleanHelper(v8::Isolate * pIsolate,bool b)79 v8::Local<v8::Boolean> NewBooleanHelper(v8::Isolate* pIsolate, bool b) {
80 return v8::Boolean::New(pIsolate, b);
81 }
82
NewStringHelper(v8::Isolate * pIsolate,ByteStringView str)83 v8::Local<v8::String> NewStringHelper(v8::Isolate* pIsolate,
84 ByteStringView str) {
85 return v8::String::NewFromUtf8(
86 pIsolate, str.unterminated_c_str(), v8::NewStringType::kNormal,
87 pdfium::base::checked_cast<int>(str.GetLength()))
88 .ToLocalChecked();
89 }
90
NewStringHelper(v8::Isolate * pIsolate,WideStringView str)91 v8::Local<v8::String> NewStringHelper(v8::Isolate* pIsolate,
92 WideStringView str) {
93 return NewStringHelper(pIsolate, FX_UTF8Encode(str).AsStringView());
94 }
95
NewArrayHelper(v8::Isolate * pIsolate)96 v8::Local<v8::Array> NewArrayHelper(v8::Isolate* pIsolate) {
97 return v8::Array::New(pIsolate);
98 }
99
NewArrayHelper(v8::Isolate * pIsolate,pdfium::span<v8::Local<v8::Value>> values)100 v8::Local<v8::Array> NewArrayHelper(v8::Isolate* pIsolate,
101 pdfium::span<v8::Local<v8::Value>> values) {
102 v8::Local<v8::Array> result = NewArrayHelper(pIsolate);
103 for (size_t i = 0; i < values.size(); ++i) {
104 fxv8::ReentrantPutArrayElementHelper(
105 pIsolate, result, i,
106 values[i].IsEmpty() ? fxv8::NewUndefinedHelper(pIsolate) : values[i]);
107 }
108 return result;
109 }
110
NewObjectHelper(v8::Isolate * pIsolate)111 v8::Local<v8::Object> NewObjectHelper(v8::Isolate* pIsolate) {
112 return v8::Object::New(pIsolate);
113 }
114
NewDateHelper(v8::Isolate * pIsolate,double d)115 v8::Local<v8::Date> NewDateHelper(v8::Isolate* pIsolate, double d) {
116 return v8::Date::New(pIsolate->GetCurrentContext(), d)
117 .ToLocalChecked()
118 .As<v8::Date>();
119 }
120
ToWideString(v8::Isolate * pIsolate,v8::Local<v8::String> pValue)121 WideString ToWideString(v8::Isolate* pIsolate, v8::Local<v8::String> pValue) {
122 v8::String::Utf8Value s(pIsolate, pValue);
123 return WideString::FromUTF8(ByteStringView(*s, s.length()));
124 }
125
ToByteString(v8::Isolate * pIsolate,v8::Local<v8::String> pValue)126 ByteString ToByteString(v8::Isolate* pIsolate, v8::Local<v8::String> pValue) {
127 v8::String::Utf8Value s(pIsolate, pValue);
128 return ByteString(*s, s.length());
129 }
130
ReentrantToInt32Helper(v8::Isolate * pIsolate,v8::Local<v8::Value> pValue)131 int ReentrantToInt32Helper(v8::Isolate* pIsolate, v8::Local<v8::Value> pValue) {
132 if (pValue.IsEmpty())
133 return 0;
134 v8::TryCatch squash_exceptions(pIsolate);
135 return pValue->Int32Value(pIsolate->GetCurrentContext()).FromMaybe(0);
136 }
137
ReentrantToBooleanHelper(v8::Isolate * pIsolate,v8::Local<v8::Value> pValue)138 bool ReentrantToBooleanHelper(v8::Isolate* pIsolate,
139 v8::Local<v8::Value> pValue) {
140 if (pValue.IsEmpty())
141 return false;
142 v8::TryCatch squash_exceptions(pIsolate);
143 return pValue->BooleanValue(pIsolate);
144 }
145
ReentrantToFloatHelper(v8::Isolate * pIsolate,v8::Local<v8::Value> pValue)146 float ReentrantToFloatHelper(v8::Isolate* pIsolate,
147 v8::Local<v8::Value> pValue) {
148 return static_cast<float>(ReentrantToDoubleHelper(pIsolate, pValue));
149 }
150
ReentrantToDoubleHelper(v8::Isolate * pIsolate,v8::Local<v8::Value> pValue)151 double ReentrantToDoubleHelper(v8::Isolate* pIsolate,
152 v8::Local<v8::Value> pValue) {
153 if (pValue.IsEmpty())
154 return 0.0;
155 v8::TryCatch squash_exceptions(pIsolate);
156 return pValue->NumberValue(pIsolate->GetCurrentContext()).FromMaybe(0.0);
157 }
158
ReentrantToWideStringHelper(v8::Isolate * pIsolate,v8::Local<v8::Value> pValue)159 WideString ReentrantToWideStringHelper(v8::Isolate* pIsolate,
160 v8::Local<v8::Value> pValue) {
161 if (pValue.IsEmpty())
162 return WideString();
163
164 v8::TryCatch squash_exceptions(pIsolate);
165 v8::MaybeLocal<v8::String> maybe_string =
166 pValue->ToString(pIsolate->GetCurrentContext());
167 if (maybe_string.IsEmpty())
168 return WideString();
169
170 return ToWideString(pIsolate, maybe_string.ToLocalChecked());
171 }
172
ReentrantToByteStringHelper(v8::Isolate * pIsolate,v8::Local<v8::Value> pValue)173 ByteString ReentrantToByteStringHelper(v8::Isolate* pIsolate,
174 v8::Local<v8::Value> pValue) {
175 if (pValue.IsEmpty())
176 return ByteString();
177
178 v8::TryCatch squash_exceptions(pIsolate);
179 v8::MaybeLocal<v8::String> maybe_string =
180 pValue->ToString(pIsolate->GetCurrentContext());
181 if (maybe_string.IsEmpty())
182 return ByteString();
183
184 return ToByteString(pIsolate, maybe_string.ToLocalChecked());
185 }
186
ReentrantToObjectHelper(v8::Isolate * pIsolate,v8::Local<v8::Value> pValue)187 v8::Local<v8::Object> ReentrantToObjectHelper(v8::Isolate* pIsolate,
188 v8::Local<v8::Value> pValue) {
189 if (!fxv8::IsObject(pValue))
190 return v8::Local<v8::Object>();
191
192 v8::TryCatch squash_exceptions(pIsolate);
193 v8::Local<v8::Context> context = pIsolate->GetCurrentContext();
194 return pValue->ToObject(context).ToLocalChecked();
195 }
196
ReentrantToArrayHelper(v8::Isolate * pIsolate,v8::Local<v8::Value> pValue)197 v8::Local<v8::Array> ReentrantToArrayHelper(v8::Isolate* pIsolate,
198 v8::Local<v8::Value> pValue) {
199 if (!fxv8::IsArray(pValue))
200 return v8::Local<v8::Array>();
201
202 v8::TryCatch squash_exceptions(pIsolate);
203 v8::Local<v8::Context> context = pIsolate->GetCurrentContext();
204 return v8::Local<v8::Array>::Cast(pValue->ToObject(context).ToLocalChecked());
205 }
206
ReentrantGetObjectPropertyHelper(v8::Isolate * pIsolate,v8::Local<v8::Object> pObj,ByteStringView bsUTF8PropertyName)207 v8::Local<v8::Value> ReentrantGetObjectPropertyHelper(
208 v8::Isolate* pIsolate,
209 v8::Local<v8::Object> pObj,
210 ByteStringView bsUTF8PropertyName) {
211 if (pObj.IsEmpty())
212 return v8::Local<v8::Value>();
213
214 v8::TryCatch squash_exceptions(pIsolate);
215 v8::Local<v8::Value> val;
216 if (!pObj->Get(pIsolate->GetCurrentContext(),
217 NewStringHelper(pIsolate, bsUTF8PropertyName))
218 .ToLocal(&val)) {
219 return v8::Local<v8::Value>();
220 }
221 return val;
222 }
223
ReentrantGetObjectPropertyNamesHelper(v8::Isolate * pIsolate,v8::Local<v8::Object> pObj)224 std::vector<WideString> ReentrantGetObjectPropertyNamesHelper(
225 v8::Isolate* pIsolate,
226 v8::Local<v8::Object> pObj) {
227 if (pObj.IsEmpty())
228 return std::vector<WideString>();
229
230 v8::TryCatch squash_exceptions(pIsolate);
231 v8::Local<v8::Array> val;
232 v8::Local<v8::Context> context = pIsolate->GetCurrentContext();
233 if (!pObj->GetPropertyNames(context).ToLocal(&val))
234 return std::vector<WideString>();
235
236 std::vector<WideString> result;
237 for (uint32_t i = 0; i < val->Length(); ++i) {
238 result.push_back(ReentrantToWideStringHelper(
239 pIsolate, val->Get(context, i).ToLocalChecked()));
240 }
241 return result;
242 }
243
ReentrantHasObjectOwnPropertyHelper(v8::Isolate * pIsolate,v8::Local<v8::Object> pObj,ByteStringView bsUTF8PropertyName)244 bool ReentrantHasObjectOwnPropertyHelper(v8::Isolate* pIsolate,
245 v8::Local<v8::Object> pObj,
246 ByteStringView bsUTF8PropertyName) {
247 if (pObj.IsEmpty())
248 return false;
249
250 v8::TryCatch squash_exceptions(pIsolate);
251 v8::Local<v8::Context> pContext = pIsolate->GetCurrentContext();
252 v8::Local<v8::String> hKey =
253 fxv8::NewStringHelper(pIsolate, bsUTF8PropertyName);
254 return pObj->HasRealNamedProperty(pContext, hKey).FromJust();
255 }
256
ReentrantSetObjectOwnPropertyHelper(v8::Isolate * pIsolate,v8::Local<v8::Object> pObj,ByteStringView bsUTF8PropertyName,v8::Local<v8::Value> pValue)257 bool ReentrantSetObjectOwnPropertyHelper(v8::Isolate* pIsolate,
258 v8::Local<v8::Object> pObj,
259 ByteStringView bsUTF8PropertyName,
260 v8::Local<v8::Value> pValue) {
261 if (pObj.IsEmpty() || pValue.IsEmpty())
262 return false;
263
264 v8::TryCatch squash_exceptions(pIsolate);
265 v8::Local<v8::String> name = NewStringHelper(pIsolate, bsUTF8PropertyName);
266 return pObj->DefineOwnProperty(pIsolate->GetCurrentContext(), name, pValue)
267 .FromMaybe(false);
268 }
269
ReentrantPutObjectPropertyHelper(v8::Isolate * pIsolate,v8::Local<v8::Object> pObj,ByteStringView bsUTF8PropertyName,v8::Local<v8::Value> pPut)270 bool ReentrantPutObjectPropertyHelper(v8::Isolate* pIsolate,
271 v8::Local<v8::Object> pObj,
272 ByteStringView bsUTF8PropertyName,
273 v8::Local<v8::Value> pPut) {
274 if (pObj.IsEmpty() || pPut.IsEmpty())
275 return false;
276
277 v8::TryCatch squash_exceptions(pIsolate);
278 v8::Local<v8::String> name = NewStringHelper(pIsolate, bsUTF8PropertyName);
279 v8::Maybe<bool> result = pObj->Set(pIsolate->GetCurrentContext(), name, pPut);
280 return result.IsJust() && result.FromJust();
281 }
282
ReentrantDeleteObjectPropertyHelper(v8::Isolate * pIsolate,v8::Local<v8::Object> pObj,ByteStringView bsUTF8PropertyName)283 void ReentrantDeleteObjectPropertyHelper(v8::Isolate* pIsolate,
284 v8::Local<v8::Object> pObj,
285 ByteStringView bsUTF8PropertyName) {
286 v8::TryCatch squash_exceptions(pIsolate);
287 pObj->Delete(pIsolate->GetCurrentContext(),
288 fxv8::NewStringHelper(pIsolate, bsUTF8PropertyName))
289 .FromJust();
290 }
291
ReentrantPutArrayElementHelper(v8::Isolate * pIsolate,v8::Local<v8::Array> pArray,size_t index,v8::Local<v8::Value> pValue)292 bool ReentrantPutArrayElementHelper(v8::Isolate* pIsolate,
293 v8::Local<v8::Array> pArray,
294 size_t index,
295 v8::Local<v8::Value> pValue) {
296 if (pArray.IsEmpty())
297 return false;
298
299 v8::TryCatch squash_exceptions(pIsolate);
300 v8::Maybe<bool> result =
301 pArray->Set(pIsolate->GetCurrentContext(),
302 pdfium::base::checked_cast<uint32_t>(index), pValue);
303 return result.IsJust() && result.FromJust();
304 }
305
ReentrantGetArrayElementHelper(v8::Isolate * pIsolate,v8::Local<v8::Array> pArray,size_t index)306 v8::Local<v8::Value> ReentrantGetArrayElementHelper(v8::Isolate* pIsolate,
307 v8::Local<v8::Array> pArray,
308 size_t index) {
309 if (pArray.IsEmpty())
310 return v8::Local<v8::Value>();
311
312 v8::TryCatch squash_exceptions(pIsolate);
313 v8::Local<v8::Value> val;
314 if (!pArray
315 ->Get(pIsolate->GetCurrentContext(),
316 pdfium::base::checked_cast<uint32_t>(index))
317 .ToLocal(&val)) {
318 return v8::Local<v8::Value>();
319 }
320 return val;
321 }
322
GetArrayLengthHelper(v8::Local<v8::Array> pArray)323 size_t GetArrayLengthHelper(v8::Local<v8::Array> pArray) {
324 if (pArray.IsEmpty())
325 return 0;
326 return pArray->Length();
327 }
328
ThrowExceptionHelper(v8::Isolate * pIsolate,ByteStringView str)329 void ThrowExceptionHelper(v8::Isolate* pIsolate, ByteStringView str) {
330 pIsolate->ThrowException(NewStringHelper(pIsolate, str));
331 }
332
ThrowExceptionHelper(v8::Isolate * pIsolate,WideStringView str)333 void ThrowExceptionHelper(v8::Isolate* pIsolate, WideStringView str) {
334 pIsolate->ThrowException(NewStringHelper(pIsolate, str));
335 }
336
337 } // namespace fxv8
338