• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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