• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2014 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/xfa/cfxjse_value.h"
8 
9 #include <math.h>
10 
11 #include "core/fxcrt/check.h"
12 #include "fxjs/fxv8.h"
13 #include "fxjs/xfa/cfxjse_class.h"
14 #include "fxjs/xfa/cfxjse_context.h"
15 #include "fxjs/xfa/cfxjse_isolatetracker.h"
16 #include "v8/include/v8-container.h"
17 #include "v8/include/v8-exception.h"
18 #include "v8/include/v8-function.h"
19 #include "v8/include/v8-local-handle.h"
20 #include "v8/include/v8-primitive.h"
21 #include "v8/include/v8-script.h"
22 
23 namespace {
24 
ftod(float fNumber)25 double ftod(float fNumber) {
26   static_assert(sizeof(float) == 4, "float of incorrect size");
27 
28   uint32_t nFloatBits = (uint32_t&)fNumber;
29   uint8_t nExponent = (uint8_t)(nFloatBits >> 23);
30   if (nExponent == 0 || nExponent == 255)
31     return fNumber;
32 
33   int8_t nErrExp = nExponent - 150;
34   if (nErrExp >= 0)
35     return fNumber;
36 
37   double dwError = pow(2.0, nErrExp);
38   double dwErrorHalf = dwError / 2;
39   double dNumber = fNumber;
40   double dNumberAbs = fabs(fNumber);
41   double dNumberAbsMin = dNumberAbs - dwErrorHalf;
42   double dNumberAbsMax = dNumberAbs + dwErrorHalf;
43   int32_t iErrPos = 0;
44   if (floor(dNumberAbsMin) == floor(dNumberAbsMax)) {
45     dNumberAbsMin = fmod(dNumberAbsMin, 1.0);
46     dNumberAbsMax = fmod(dNumberAbsMax, 1.0);
47     int32_t iErrPosMin = 1;
48     int32_t iErrPosMax = 38;
49     do {
50       int32_t iMid = (iErrPosMin + iErrPosMax) / 2;
51       double dPow = pow(10.0, iMid);
52       if (floor(dNumberAbsMin * dPow) == floor(dNumberAbsMax * dPow)) {
53         iErrPosMin = iMid + 1;
54       } else {
55         iErrPosMax = iMid;
56       }
57     } while (iErrPosMin < iErrPosMax);
58     iErrPos = iErrPosMax;
59   }
60   double dPow = pow(10.0, iErrPos);
61   return fNumber < 0 ? ceil(dNumber * dPow - 0.5) / dPow
62                      : floor(dNumber * dPow + 0.5) / dPow;
63 }
64 
65 }  // namespace
66 
FXJSE_ThrowMessage(v8::Isolate * pIsolate,ByteStringView utf8Message)67 void FXJSE_ThrowMessage(v8::Isolate* pIsolate, ByteStringView utf8Message) {
68   DCHECK(pIsolate);
69   CFXJSE_ScopeUtil_IsolateHandleRootContext scope(pIsolate);
70   v8::Local<v8::String> hMessage = fxv8::NewStringHelper(pIsolate, utf8Message);
71   v8::Local<v8::Value> hError = v8::Exception::Error(hMessage);
72   pIsolate->ThrowException(hError);
73 }
74 
75 CFXJSE_Value::CFXJSE_Value() = default;
76 
CFXJSE_Value(v8::Isolate * pIsolate,v8::Local<v8::Value> value)77 CFXJSE_Value::CFXJSE_Value(v8::Isolate* pIsolate, v8::Local<v8::Value> value) {
78   ForceSetValue(pIsolate, value);
79 }
80 
81 CFXJSE_Value::~CFXJSE_Value() = default;
82 
ToHostObject(v8::Isolate * pIsolate) const83 CFXJSE_HostObject* CFXJSE_Value::ToHostObject(v8::Isolate* pIsolate) const {
84   CFXJSE_ScopeUtil_IsolateHandleRootContext scope(pIsolate);
85   return CFXJSE_HostObject::FromV8(
86       v8::Local<v8::Value>::New(pIsolate, m_hValue));
87 }
88 
SetHostObject(v8::Isolate * pIsolate,CFXJSE_HostObject * pObject,CFXJSE_Class * pClass)89 void CFXJSE_Value::SetHostObject(v8::Isolate* pIsolate,
90                                  CFXJSE_HostObject* pObject,
91                                  CFXJSE_Class* pClass) {
92   CFXJSE_ScopeUtil_IsolateHandleRootContext scope(pIsolate);
93   m_hValue.Reset(pIsolate, pObject->NewBoundV8Object(
94                                pIsolate, pClass->GetTemplate(pIsolate)));
95 }
96 
SetArray(v8::Isolate * pIsolate,const std::vector<std::unique_ptr<CFXJSE_Value>> & values)97 void CFXJSE_Value::SetArray(
98     v8::Isolate* pIsolate,
99     const std::vector<std::unique_ptr<CFXJSE_Value>>& values) {
100   CFXJSE_ScopeUtil_IsolateHandleRootContext scope(pIsolate);
101   v8::LocalVector<v8::Value> local_values(pIsolate);
102   local_values.reserve(values.size());
103   for (auto& v : values) {
104     if (v->IsEmpty())
105       local_values.push_back(fxv8::NewUndefinedHelper(pIsolate));
106     else
107       local_values.push_back(v->GetValue(pIsolate));
108   }
109   v8::Local<v8::Array> hArrayObject =
110       v8::Array::New(pIsolate, local_values.data(), local_values.size());
111   m_hValue.Reset(pIsolate, hArrayObject);
112 }
113 
SetFloat(v8::Isolate * pIsolate,float fFloat)114 void CFXJSE_Value::SetFloat(v8::Isolate* pIsolate, float fFloat) {
115   CFXJSE_ScopeUtil_IsolateHandle scope(pIsolate);
116   m_hValue.Reset(pIsolate, fxv8::NewNumberHelper(pIsolate, ftod(fFloat)));
117 }
118 
SetObjectProperty(v8::Isolate * pIsolate,ByteStringView szPropName,CFXJSE_Value * pPropValue)119 bool CFXJSE_Value::SetObjectProperty(v8::Isolate* pIsolate,
120                                      ByteStringView szPropName,
121                                      CFXJSE_Value* pPropValue) {
122   if (pPropValue->IsEmpty())
123     return false;
124 
125   CFXJSE_ScopeUtil_IsolateHandleRootContext scope(pIsolate);
126   v8::Local<v8::Value> hObject = GetValue(pIsolate);
127   if (!hObject->IsObject())
128     return false;
129 
130   return fxv8::ReentrantPutObjectPropertyHelper(
131       pIsolate, hObject.As<v8::Object>(), szPropName,
132       pPropValue->GetValue(pIsolate));
133 }
134 
GetObjectProperty(v8::Isolate * pIsolate,ByteStringView szPropName,CFXJSE_Value * pPropValue)135 bool CFXJSE_Value::GetObjectProperty(v8::Isolate* pIsolate,
136                                      ByteStringView szPropName,
137                                      CFXJSE_Value* pPropValue) {
138   CFXJSE_ScopeUtil_IsolateHandleRootContext scope(pIsolate);
139   v8::Local<v8::Value> hObject = GetValue(pIsolate);
140   if (!hObject->IsObject())
141     return false;
142 
143   pPropValue->ForceSetValue(
144       pIsolate, fxv8::ReentrantGetObjectPropertyHelper(
145                     pIsolate, hObject.As<v8::Object>(), szPropName));
146   return true;
147 }
148 
GetObjectPropertyByIdx(v8::Isolate * pIsolate,uint32_t uPropIdx,CFXJSE_Value * pPropValue)149 bool CFXJSE_Value::GetObjectPropertyByIdx(v8::Isolate* pIsolate,
150                                           uint32_t uPropIdx,
151                                           CFXJSE_Value* pPropValue) {
152   CFXJSE_ScopeUtil_IsolateHandleRootContext scope(pIsolate);
153   v8::Local<v8::Value> hObject = GetValue(pIsolate);
154   if (!hObject->IsArray())
155     return false;
156 
157   pPropValue->ForceSetValue(pIsolate,
158                             fxv8::ReentrantGetArrayElementHelper(
159                                 pIsolate, hObject.As<v8::Array>(), uPropIdx));
160   return true;
161 }
162 
DeleteObjectProperty(v8::Isolate * pIsolate,ByteStringView szPropName)163 void CFXJSE_Value::DeleteObjectProperty(v8::Isolate* pIsolate,
164                                         ByteStringView szPropName) {
165   CFXJSE_ScopeUtil_IsolateHandleRootContext scope(pIsolate);
166   v8::Local<v8::Value> hObject = v8::Local<v8::Value>::New(pIsolate, m_hValue);
167   if (hObject->IsObject()) {
168     fxv8::ReentrantDeleteObjectPropertyHelper(
169         pIsolate, hObject.As<v8::Object>(), szPropName);
170   }
171 }
172 
SetObjectOwnProperty(v8::Isolate * pIsolate,ByteStringView szPropName,CFXJSE_Value * pPropValue)173 bool CFXJSE_Value::SetObjectOwnProperty(v8::Isolate* pIsolate,
174                                         ByteStringView szPropName,
175                                         CFXJSE_Value* pPropValue) {
176   CFXJSE_ScopeUtil_IsolateHandleRootContext scope(pIsolate);
177   v8::Local<v8::Value> hObject = v8::Local<v8::Value>::New(pIsolate, m_hValue);
178   if (!hObject->IsObject())
179     return false;
180 
181   v8::Local<v8::Value> pValue =
182       v8::Local<v8::Value>::New(pIsolate, pPropValue->m_hValue);
183   return fxv8::ReentrantSetObjectOwnPropertyHelper(
184       pIsolate, hObject.As<v8::Object>(), szPropName, pValue);
185 }
186 
NewBoundFunction(v8::Isolate * pIsolate,v8::Local<v8::Function> hOldFunction,v8::Local<v8::Object> hNewThis)187 v8::Local<v8::Function> CFXJSE_Value::NewBoundFunction(
188     v8::Isolate* pIsolate,
189     v8::Local<v8::Function> hOldFunction,
190     v8::Local<v8::Object> hNewThis) {
191   DCHECK(!hOldFunction.IsEmpty());
192   DCHECK(!hNewThis.IsEmpty());
193 
194   CFXJSE_ScopeUtil_RootContext scope(pIsolate);
195   v8::Local<v8::Value> rgArgs[2];
196   rgArgs[0] = hOldFunction;
197   rgArgs[1] = hNewThis;
198   v8::Local<v8::String> hBinderFuncSource = fxv8::NewStringHelper(
199       pIsolate, "(function (fn, obj) { return fn.bind(obj); })");
200   v8::Local<v8::Context> hContext = pIsolate->GetCurrentContext();
201   v8::Local<v8::Function> hBinderFunc =
202       v8::Script::Compile(hContext, hBinderFuncSource)
203           .ToLocalChecked()
204           ->Run(hContext)
205           .ToLocalChecked()
206           .As<v8::Function>();
207   v8::Local<v8::Value> hBoundFunction =
208       hBinderFunc->Call(hContext, hContext->Global(), 2, rgArgs)
209           .ToLocalChecked();
210   if (!fxv8::IsFunction(hBoundFunction))
211     return v8::Local<v8::Function>();
212 
213   return hBoundFunction.As<v8::Function>();
214 }
215 
GetValue(v8::Isolate * pIsolate) const216 v8::Local<v8::Value> CFXJSE_Value::GetValue(v8::Isolate* pIsolate) const {
217   return v8::Local<v8::Value>::New(pIsolate, m_hValue);
218 }
219 
IsEmpty() const220 bool CFXJSE_Value::IsEmpty() const {
221   return m_hValue.IsEmpty();
222 }
223 
IsUndefined(v8::Isolate * pIsolate) const224 bool CFXJSE_Value::IsUndefined(v8::Isolate* pIsolate) const {
225   if (IsEmpty())
226     return false;
227 
228   CFXJSE_ScopeUtil_IsolateHandle scope(pIsolate);
229   v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(pIsolate, m_hValue);
230   return hValue->IsUndefined();
231 }
232 
IsNull(v8::Isolate * pIsolate) const233 bool CFXJSE_Value::IsNull(v8::Isolate* pIsolate) const {
234   if (IsEmpty())
235     return false;
236 
237   CFXJSE_ScopeUtil_IsolateHandle scope(pIsolate);
238   v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(pIsolate, m_hValue);
239   return hValue->IsNull();
240 }
241 
IsBoolean(v8::Isolate * pIsolate) const242 bool CFXJSE_Value::IsBoolean(v8::Isolate* pIsolate) const {
243   if (IsEmpty())
244     return false;
245 
246   CFXJSE_ScopeUtil_IsolateHandle scope(pIsolate);
247   v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(pIsolate, m_hValue);
248   return hValue->IsBoolean();
249 }
250 
IsString(v8::Isolate * pIsolate) const251 bool CFXJSE_Value::IsString(v8::Isolate* pIsolate) const {
252   if (IsEmpty())
253     return false;
254 
255   CFXJSE_ScopeUtil_IsolateHandle scope(pIsolate);
256   v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(pIsolate, m_hValue);
257   return hValue->IsString();
258 }
259 
IsNumber(v8::Isolate * pIsolate) const260 bool CFXJSE_Value::IsNumber(v8::Isolate* pIsolate) const {
261   if (IsEmpty())
262     return false;
263 
264   CFXJSE_ScopeUtil_IsolateHandle scope(pIsolate);
265   v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(pIsolate, m_hValue);
266   return hValue->IsNumber();
267 }
268 
IsInteger(v8::Isolate * pIsolate) const269 bool CFXJSE_Value::IsInteger(v8::Isolate* pIsolate) const {
270   if (IsEmpty())
271     return false;
272 
273   CFXJSE_ScopeUtil_IsolateHandle scope(pIsolate);
274   v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(pIsolate, m_hValue);
275   return hValue->IsInt32();
276 }
277 
IsObject(v8::Isolate * pIsolate) const278 bool CFXJSE_Value::IsObject(v8::Isolate* pIsolate) const {
279   if (IsEmpty())
280     return false;
281 
282   CFXJSE_ScopeUtil_IsolateHandle scope(pIsolate);
283   v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(pIsolate, m_hValue);
284   return hValue->IsObject();
285 }
286 
IsArray(v8::Isolate * pIsolate) const287 bool CFXJSE_Value::IsArray(v8::Isolate* pIsolate) const {
288   if (IsEmpty())
289     return false;
290 
291   CFXJSE_ScopeUtil_IsolateHandle scope(pIsolate);
292   v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(pIsolate, m_hValue);
293   return hValue->IsArray();
294 }
295 
IsFunction(v8::Isolate * pIsolate) const296 bool CFXJSE_Value::IsFunction(v8::Isolate* pIsolate) const {
297   if (IsEmpty())
298     return false;
299 
300   CFXJSE_ScopeUtil_IsolateHandle scope(pIsolate);
301   v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(pIsolate, m_hValue);
302   return hValue->IsFunction();
303 }
304 
ToBoolean(v8::Isolate * pIsolate) const305 bool CFXJSE_Value::ToBoolean(v8::Isolate* pIsolate) const {
306   DCHECK(!IsEmpty());
307   CFXJSE_ScopeUtil_IsolateHandleRootContext scope(pIsolate);
308   return fxv8::ReentrantToBooleanHelper(
309       pIsolate, v8::Local<v8::Value>::New(pIsolate, m_hValue));
310 }
311 
ToFloat(v8::Isolate * pIsolate) const312 float CFXJSE_Value::ToFloat(v8::Isolate* pIsolate) const {
313   return static_cast<float>(ToDouble(pIsolate));
314 }
315 
ToDouble(v8::Isolate * pIsolate) const316 double CFXJSE_Value::ToDouble(v8::Isolate* pIsolate) const {
317   DCHECK(!IsEmpty());
318   CFXJSE_ScopeUtil_IsolateHandleRootContext scope(pIsolate);
319   return fxv8::ReentrantToDoubleHelper(
320       pIsolate, v8::Local<v8::Value>::New(pIsolate, m_hValue));
321 }
322 
ToInteger(v8::Isolate * pIsolate) const323 int32_t CFXJSE_Value::ToInteger(v8::Isolate* pIsolate) const {
324   DCHECK(!IsEmpty());
325   CFXJSE_ScopeUtil_IsolateHandleRootContext scope(pIsolate);
326   return fxv8::ReentrantToInt32Helper(
327       pIsolate, v8::Local<v8::Value>::New(pIsolate, m_hValue));
328 }
329 
ToString(v8::Isolate * pIsolate) const330 ByteString CFXJSE_Value::ToString(v8::Isolate* pIsolate) const {
331   DCHECK(!IsEmpty());
332   CFXJSE_ScopeUtil_IsolateHandleRootContext scope(pIsolate);
333   return fxv8::ReentrantToByteStringHelper(
334       pIsolate, v8::Local<v8::Value>::New(pIsolate, m_hValue));
335 }
336 
SetUndefined(v8::Isolate * pIsolate)337 void CFXJSE_Value::SetUndefined(v8::Isolate* pIsolate) {
338   CFXJSE_ScopeUtil_IsolateHandle scope(pIsolate);
339   m_hValue.Reset(pIsolate, fxv8::NewUndefinedHelper(pIsolate));
340 }
341 
SetNull(v8::Isolate * pIsolate)342 void CFXJSE_Value::SetNull(v8::Isolate* pIsolate) {
343   CFXJSE_ScopeUtil_IsolateHandle scope(pIsolate);
344   m_hValue.Reset(pIsolate, fxv8::NewNullHelper(pIsolate));
345 }
346 
SetBoolean(v8::Isolate * pIsolate,bool bBoolean)347 void CFXJSE_Value::SetBoolean(v8::Isolate* pIsolate, bool bBoolean) {
348   CFXJSE_ScopeUtil_IsolateHandle scope(pIsolate);
349   m_hValue.Reset(pIsolate, fxv8::NewBooleanHelper(pIsolate, bBoolean));
350 }
351 
SetInteger(v8::Isolate * pIsolate,int32_t nInteger)352 void CFXJSE_Value::SetInteger(v8::Isolate* pIsolate, int32_t nInteger) {
353   CFXJSE_ScopeUtil_IsolateHandle scope(pIsolate);
354   m_hValue.Reset(pIsolate, fxv8::NewNumberHelper(pIsolate, nInteger));
355 }
356 
SetDouble(v8::Isolate * pIsolate,double dDouble)357 void CFXJSE_Value::SetDouble(v8::Isolate* pIsolate, double dDouble) {
358   CFXJSE_ScopeUtil_IsolateHandle scope(pIsolate);
359   m_hValue.Reset(pIsolate, fxv8::NewNumberHelper(pIsolate, dDouble));
360 }
361 
SetString(v8::Isolate * pIsolate,ByteStringView szString)362 void CFXJSE_Value::SetString(v8::Isolate* pIsolate, ByteStringView szString) {
363   CFXJSE_ScopeUtil_IsolateHandle scope(pIsolate);
364   m_hValue.Reset(pIsolate, fxv8::NewStringHelper(pIsolate, szString));
365 }
366