1 // Copyright 2014 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/cfxjse_value.h" 8 9 #include <math.h> 10 11 #include "fxjs/cfxjse_class.h" 12 #include "fxjs/cfxjse_context.h" 13 14 namespace { 15 16 double ftod(float fNumber) { 17 static_assert(sizeof(float) == 4, "float of incorrect size"); 18 19 uint32_t nFloatBits = (uint32_t&)fNumber; 20 uint8_t nExponent = (uint8_t)(nFloatBits >> 23); 21 if (nExponent == 0 || nExponent == 255) 22 return fNumber; 23 24 int8_t nErrExp = nExponent - 150; 25 if (nErrExp >= 0) 26 return fNumber; 27 28 double dwError = pow(2.0, nErrExp), dwErrorHalf = dwError / 2; 29 double dNumber = fNumber, dNumberAbs = fabs(fNumber); 30 double dNumberAbsMin = dNumberAbs - dwErrorHalf, 31 dNumberAbsMax = dNumberAbs + dwErrorHalf; 32 int32_t iErrPos = 0; 33 if (floor(dNumberAbsMin) == floor(dNumberAbsMax)) { 34 dNumberAbsMin = fmod(dNumberAbsMin, 1.0); 35 dNumberAbsMax = fmod(dNumberAbsMax, 1.0); 36 int32_t iErrPosMin = 1, iErrPosMax = 38; 37 do { 38 int32_t iMid = (iErrPosMin + iErrPosMax) / 2; 39 double dPow = pow(10.0, iMid); 40 if (floor(dNumberAbsMin * dPow) == floor(dNumberAbsMax * dPow)) { 41 iErrPosMin = iMid + 1; 42 } else { 43 iErrPosMax = iMid; 44 } 45 } while (iErrPosMin < iErrPosMax); 46 iErrPos = iErrPosMax; 47 } 48 double dPow = pow(10.0, iErrPos); 49 return fNumber < 0 ? ceil(dNumber * dPow - 0.5) / dPow 50 : floor(dNumber * dPow + 0.5) / dPow; 51 } 52 53 } // namespace 54 55 void FXJSE_ThrowMessage(const ByteStringView& utf8Message) { 56 v8::Isolate* pIsolate = v8::Isolate::GetCurrent(); 57 ASSERT(pIsolate); 58 59 CFXJSE_ScopeUtil_IsolateHandleRootContext scope(pIsolate); 60 v8::Local<v8::String> hMessage = v8::String::NewFromUtf8( 61 pIsolate, utf8Message.unterminated_c_str(), v8::String::kNormalString, 62 utf8Message.GetLength()); 63 v8::Local<v8::Value> hError = v8::Exception::Error(hMessage); 64 pIsolate->ThrowException(hError); 65 } 66 67 CFXJSE_Value::CFXJSE_Value(v8::Isolate* pIsolate) : m_pIsolate(pIsolate) {} 68 69 CFXJSE_Value::~CFXJSE_Value() {} 70 71 CFXJSE_HostObject* CFXJSE_Value::ToHostObject(CFXJSE_Class* lpClass) const { 72 ASSERT(!m_hValue.IsEmpty()); 73 74 CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate); 75 v8::Local<v8::Value> pValue = v8::Local<v8::Value>::New(m_pIsolate, m_hValue); 76 ASSERT(!pValue.IsEmpty()); 77 78 if (!pValue->IsObject()) 79 return nullptr; 80 81 return FXJSE_RetrieveObjectBinding(pValue.As<v8::Object>(), lpClass); 82 } 83 84 void CFXJSE_Value::SetObject(CFXJSE_HostObject* lpObject, 85 CFXJSE_Class* pClass) { 86 CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate); 87 v8::Local<v8::FunctionTemplate> hClass = 88 v8::Local<v8::FunctionTemplate>::New(m_pIsolate, pClass->m_hTemplate); 89 v8::Local<v8::Object> hObject = hClass->InstanceTemplate()->NewInstance(); 90 FXJSE_UpdateObjectBinding(hObject, lpObject); 91 m_hValue.Reset(m_pIsolate, hObject); 92 } 93 94 void CFXJSE_Value::SetArray( 95 const std::vector<std::unique_ptr<CFXJSE_Value>>& values) { 96 CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate); 97 v8::Local<v8::Array> hArrayObject = v8::Array::New(m_pIsolate, values.size()); 98 uint32_t count = 0; 99 for (auto& v : values) { 100 hArrayObject->Set(count++, v8::Local<v8::Value>::New( 101 m_pIsolate, v.get()->DirectGetValue())); 102 } 103 m_hValue.Reset(m_pIsolate, hArrayObject); 104 } 105 106 void CFXJSE_Value::SetDate(double dDouble) { 107 CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate); 108 v8::Local<v8::Value> hDate = v8::Date::New(m_pIsolate, dDouble); 109 m_hValue.Reset(m_pIsolate, hDate); 110 } 111 112 void CFXJSE_Value::SetFloat(float fFloat) { 113 CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate); 114 v8::Local<v8::Value> pValue = v8::Number::New(m_pIsolate, ftod(fFloat)); 115 m_hValue.Reset(m_pIsolate, pValue); 116 } 117 118 bool CFXJSE_Value::SetObjectProperty(const ByteStringView& szPropName, 119 CFXJSE_Value* lpPropValue) { 120 ASSERT(lpPropValue); 121 CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate); 122 v8::Local<v8::Value> hObject = 123 v8::Local<v8::Value>::New(m_pIsolate, m_hValue); 124 if (!hObject->IsObject()) 125 return false; 126 127 v8::Local<v8::Value> hPropValue = 128 v8::Local<v8::Value>::New(m_pIsolate, lpPropValue->DirectGetValue()); 129 return (bool)hObject.As<v8::Object>()->Set( 130 v8::String::NewFromUtf8(m_pIsolate, szPropName.unterminated_c_str(), 131 v8::String::kNormalString, 132 szPropName.GetLength()), 133 hPropValue); 134 } 135 136 bool CFXJSE_Value::GetObjectProperty(const ByteStringView& szPropName, 137 CFXJSE_Value* lpPropValue) { 138 ASSERT(lpPropValue); 139 CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate); 140 v8::Local<v8::Value> hObject = 141 v8::Local<v8::Value>::New(m_pIsolate, m_hValue); 142 if (!hObject->IsObject()) 143 return false; 144 145 v8::Local<v8::Value> hPropValue = 146 hObject.As<v8::Object>()->Get(v8::String::NewFromUtf8( 147 m_pIsolate, szPropName.unterminated_c_str(), 148 v8::String::kNormalString, szPropName.GetLength())); 149 lpPropValue->ForceSetValue(hPropValue); 150 return true; 151 } 152 153 bool CFXJSE_Value::SetObjectProperty(uint32_t uPropIdx, 154 CFXJSE_Value* lpPropValue) { 155 CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate); 156 v8::Local<v8::Value> hObject = 157 v8::Local<v8::Value>::New(m_pIsolate, m_hValue); 158 if (!hObject->IsObject()) 159 return false; 160 161 v8::Local<v8::Value> hPropValue = 162 v8::Local<v8::Value>::New(m_pIsolate, lpPropValue->DirectGetValue()); 163 return (bool)hObject.As<v8::Object>()->Set(uPropIdx, hPropValue); 164 } 165 166 bool CFXJSE_Value::GetObjectPropertyByIdx(uint32_t uPropIdx, 167 CFXJSE_Value* lpPropValue) { 168 CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate); 169 v8::Local<v8::Value> hObject = 170 v8::Local<v8::Value>::New(m_pIsolate, m_hValue); 171 if (!hObject->IsObject()) 172 return false; 173 174 v8::Local<v8::Value> hPropValue = hObject.As<v8::Object>()->Get(uPropIdx); 175 lpPropValue->ForceSetValue(hPropValue); 176 return true; 177 } 178 179 bool CFXJSE_Value::DeleteObjectProperty(const ByteStringView& szPropName) { 180 CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate); 181 v8::Local<v8::Value> hObject = 182 v8::Local<v8::Value>::New(m_pIsolate, m_hValue); 183 if (!hObject->IsObject()) 184 return false; 185 186 hObject.As<v8::Object>()->Delete(v8::String::NewFromUtf8( 187 m_pIsolate, szPropName.unterminated_c_str(), v8::String::kNormalString, 188 szPropName.GetLength())); 189 return true; 190 } 191 192 bool CFXJSE_Value::HasObjectOwnProperty(const ByteStringView& szPropName, 193 bool bUseTypeGetter) { 194 CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate); 195 v8::Local<v8::Value> hObject = 196 v8::Local<v8::Value>::New(m_pIsolate, m_hValue); 197 if (!hObject->IsObject()) 198 return false; 199 200 v8::Local<v8::String> hKey = v8::String::NewFromUtf8( 201 m_pIsolate, szPropName.unterminated_c_str(), v8::String::kNormalString, 202 szPropName.GetLength()); 203 return hObject.As<v8::Object>()->HasRealNamedProperty(hKey) || 204 (bUseTypeGetter && 205 hObject.As<v8::Object>() 206 ->HasOwnProperty(m_pIsolate->GetCurrentContext(), hKey) 207 .FromMaybe(false)); 208 } 209 210 bool CFXJSE_Value::SetObjectOwnProperty(const ByteStringView& szPropName, 211 CFXJSE_Value* lpPropValue) { 212 ASSERT(lpPropValue); 213 CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate); 214 v8::Local<v8::Value> hObject = 215 v8::Local<v8::Value>::New(m_pIsolate, m_hValue); 216 if (!hObject->IsObject()) 217 return false; 218 219 v8::Local<v8::Value> pValue = 220 v8::Local<v8::Value>::New(m_pIsolate, lpPropValue->m_hValue); 221 return hObject.As<v8::Object>() 222 ->DefineOwnProperty( 223 m_pIsolate->GetCurrentContext(), 224 v8::String::NewFromUtf8(m_pIsolate, szPropName.unterminated_c_str(), 225 v8::String::kNormalString, 226 szPropName.GetLength()), 227 pValue) 228 .FromMaybe(false); 229 } 230 231 bool CFXJSE_Value::SetFunctionBind(CFXJSE_Value* lpOldFunction, 232 CFXJSE_Value* lpNewThis) { 233 ASSERT(lpOldFunction && lpNewThis); 234 235 CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate); 236 v8::Local<v8::Value> rgArgs[2]; 237 v8::Local<v8::Value> hOldFunction = 238 v8::Local<v8::Value>::New(m_pIsolate, lpOldFunction->DirectGetValue()); 239 if (hOldFunction.IsEmpty() || !hOldFunction->IsFunction()) 240 return false; 241 242 rgArgs[0] = hOldFunction; 243 v8::Local<v8::Value> hNewThis = 244 v8::Local<v8::Value>::New(m_pIsolate, lpNewThis->DirectGetValue()); 245 if (hNewThis.IsEmpty()) 246 return false; 247 248 rgArgs[1] = hNewThis; 249 v8::Local<v8::String> hBinderFuncSource = 250 v8::String::NewFromUtf8(m_pIsolate, 251 "(function (oldfunction, newthis) { return " 252 "oldfunction.bind(newthis); })"); 253 v8::Local<v8::Function> hBinderFunc = 254 v8::Script::Compile(hBinderFuncSource)->Run().As<v8::Function>(); 255 v8::Local<v8::Value> hBoundFunction = 256 hBinderFunc->Call(m_pIsolate->GetCurrentContext()->Global(), 2, rgArgs); 257 if (hBoundFunction.IsEmpty() || !hBoundFunction->IsFunction()) 258 return false; 259 260 m_hValue.Reset(m_pIsolate, hBoundFunction); 261 return true; 262 } 263 264 bool CFXJSE_Value::IsUndefined() const { 265 if (m_hValue.IsEmpty()) 266 return false; 267 268 CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate); 269 v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(m_pIsolate, m_hValue); 270 return hValue->IsUndefined(); 271 } 272 273 bool CFXJSE_Value::IsNull() const { 274 if (m_hValue.IsEmpty()) 275 return false; 276 277 CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate); 278 v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(m_pIsolate, m_hValue); 279 return hValue->IsNull(); 280 } 281 282 bool CFXJSE_Value::IsBoolean() const { 283 if (m_hValue.IsEmpty()) 284 return false; 285 286 CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate); 287 v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(m_pIsolate, m_hValue); 288 return hValue->IsBoolean(); 289 } 290 291 bool CFXJSE_Value::IsString() const { 292 if (m_hValue.IsEmpty()) 293 return false; 294 295 CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate); 296 v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(m_pIsolate, m_hValue); 297 return hValue->IsString(); 298 } 299 300 bool CFXJSE_Value::IsNumber() const { 301 if (m_hValue.IsEmpty()) 302 return false; 303 304 CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate); 305 v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(m_pIsolate, m_hValue); 306 return hValue->IsNumber(); 307 } 308 309 bool CFXJSE_Value::IsInteger() const { 310 if (m_hValue.IsEmpty()) 311 return false; 312 313 CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate); 314 v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(m_pIsolate, m_hValue); 315 return hValue->IsInt32(); 316 } 317 318 bool CFXJSE_Value::IsObject() const { 319 if (m_hValue.IsEmpty()) 320 return false; 321 322 CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate); 323 v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(m_pIsolate, m_hValue); 324 return hValue->IsObject(); 325 } 326 327 bool CFXJSE_Value::IsArray() const { 328 if (m_hValue.IsEmpty()) 329 return false; 330 331 CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate); 332 v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(m_pIsolate, m_hValue); 333 return hValue->IsArray(); 334 } 335 336 bool CFXJSE_Value::IsFunction() const { 337 if (m_hValue.IsEmpty()) 338 return false; 339 340 CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate); 341 v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(m_pIsolate, m_hValue); 342 return hValue->IsFunction(); 343 } 344 345 bool CFXJSE_Value::IsDate() const { 346 if (m_hValue.IsEmpty()) 347 return false; 348 349 CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate); 350 v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(m_pIsolate, m_hValue); 351 return hValue->IsDate(); 352 } 353 354 bool CFXJSE_Value::ToBoolean() const { 355 ASSERT(!m_hValue.IsEmpty()); 356 CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate); 357 v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(m_pIsolate, m_hValue); 358 return static_cast<bool>(hValue->BooleanValue()); 359 } 360 361 float CFXJSE_Value::ToFloat() const { 362 ASSERT(!m_hValue.IsEmpty()); 363 CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate); 364 v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(m_pIsolate, m_hValue); 365 return static_cast<float>(hValue->NumberValue()); 366 } 367 368 double CFXJSE_Value::ToDouble() const { 369 ASSERT(!m_hValue.IsEmpty()); 370 CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate); 371 v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(m_pIsolate, m_hValue); 372 return static_cast<double>(hValue->NumberValue()); 373 } 374 375 int32_t CFXJSE_Value::ToInteger() const { 376 ASSERT(!m_hValue.IsEmpty()); 377 CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate); 378 v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(m_pIsolate, m_hValue); 379 return static_cast<int32_t>(hValue->NumberValue()); 380 } 381 382 ByteString CFXJSE_Value::ToString() const { 383 ASSERT(!m_hValue.IsEmpty()); 384 CFXJSE_ScopeUtil_IsolateHandleRootContext scope(m_pIsolate); 385 v8::Local<v8::Value> hValue = v8::Local<v8::Value>::New(m_pIsolate, m_hValue); 386 v8::Local<v8::String> hString = hValue->ToString(); 387 v8::String::Utf8Value hStringVal(m_pIsolate, hString); 388 return ByteString(*hStringVal); 389 } 390 391 void CFXJSE_Value::SetUndefined() { 392 CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate); 393 v8::Local<v8::Value> hValue = v8::Undefined(m_pIsolate); 394 m_hValue.Reset(m_pIsolate, hValue); 395 } 396 397 void CFXJSE_Value::SetNull() { 398 CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate); 399 v8::Local<v8::Value> hValue = v8::Null(m_pIsolate); 400 m_hValue.Reset(m_pIsolate, hValue); 401 } 402 403 void CFXJSE_Value::SetBoolean(bool bBoolean) { 404 CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate); 405 v8::Local<v8::Value> hValue = v8::Boolean::New(m_pIsolate, bBoolean != false); 406 m_hValue.Reset(m_pIsolate, hValue); 407 } 408 409 void CFXJSE_Value::SetInteger(int32_t nInteger) { 410 CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate); 411 v8::Local<v8::Value> hValue = v8::Integer::New(m_pIsolate, nInteger); 412 m_hValue.Reset(m_pIsolate, hValue); 413 } 414 415 void CFXJSE_Value::SetDouble(double dDouble) { 416 CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate); 417 v8::Local<v8::Value> hValue = v8::Number::New(m_pIsolate, dDouble); 418 m_hValue.Reset(m_pIsolate, hValue); 419 } 420 421 void CFXJSE_Value::SetString(const ByteStringView& szString) { 422 CFXJSE_ScopeUtil_IsolateHandle scope(m_pIsolate); 423 v8::Local<v8::Value> hValue = v8::String::NewFromUtf8( 424 m_pIsolate, reinterpret_cast<const char*>(szString.raw_str()), 425 v8::String::kNormalString, szString.GetLength()); 426 m_hValue.Reset(m_pIsolate, hValue); 427 } 428 429