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