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