|  | // Copyright 2020 PDFium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com | 
|  |  | 
|  | #include "fxjs/fxv8.h" | 
|  |  | 
|  | namespace fxv8 { | 
|  |  | 
|  | bool IsUndefined(v8::Local<v8::Value> value) { | 
|  | return !value.IsEmpty() && value->IsUndefined(); | 
|  | } | 
|  |  | 
|  | bool IsNull(v8::Local<v8::Value> value) { | 
|  | return !value.IsEmpty() && value->IsNull(); | 
|  | } | 
|  |  | 
|  | bool IsBoolean(v8::Local<v8::Value> value) { | 
|  | return !value.IsEmpty() && value->IsBoolean(); | 
|  | } | 
|  |  | 
|  | bool IsString(v8::Local<v8::Value> value) { | 
|  | return !value.IsEmpty() && value->IsString(); | 
|  | } | 
|  |  | 
|  | bool IsNumber(v8::Local<v8::Value> value) { | 
|  | return !value.IsEmpty() && value->IsNumber(); | 
|  | } | 
|  |  | 
|  | bool IsInteger(v8::Local<v8::Value> value) { | 
|  | return !value.IsEmpty() && value->IsInt32(); | 
|  | } | 
|  |  | 
|  | bool IsObject(v8::Local<v8::Value> value) { | 
|  | return !value.IsEmpty() && value->IsObject(); | 
|  | } | 
|  |  | 
|  | bool IsArray(v8::Local<v8::Value> value) { | 
|  | return !value.IsEmpty() && value->IsArray(); | 
|  | } | 
|  |  | 
|  | bool IsDate(v8::Local<v8::Value> value) { | 
|  | return !value.IsEmpty() && value->IsDate(); | 
|  | } | 
|  |  | 
|  | bool IsFunction(v8::Local<v8::Value> value) { | 
|  | return !value.IsEmpty() && value->IsFunction(); | 
|  | } | 
|  |  | 
|  | v8::Local<v8::Value> NewNullHelper(v8::Isolate* pIsolate) { | 
|  | return v8::Null(pIsolate); | 
|  | } | 
|  |  | 
|  | v8::Local<v8::Value> NewUndefinedHelper(v8::Isolate* pIsolate) { | 
|  | return v8::Undefined(pIsolate); | 
|  | } | 
|  |  | 
|  | v8::Local<v8::Number> NewNumberHelper(v8::Isolate* pIsolate, int number) { | 
|  | return v8::Int32::New(pIsolate, number); | 
|  | } | 
|  |  | 
|  | v8::Local<v8::Number> NewNumberHelper(v8::Isolate* pIsolate, double number) { | 
|  | return v8::Number::New(pIsolate, number); | 
|  | } | 
|  |  | 
|  | v8::Local<v8::Number> NewNumberHelper(v8::Isolate* pIsolate, float number) { | 
|  | return v8::Number::New(pIsolate, number); | 
|  | } | 
|  |  | 
|  | v8::Local<v8::Boolean> NewBooleanHelper(v8::Isolate* pIsolate, bool b) { | 
|  | return v8::Boolean::New(pIsolate, b); | 
|  | } | 
|  |  | 
|  | v8::Local<v8::String> NewStringHelper(v8::Isolate* pIsolate, | 
|  | ByteStringView str) { | 
|  | return v8::String::NewFromUtf8(pIsolate, str.unterminated_c_str(), | 
|  | v8::NewStringType::kNormal, str.GetLength()) | 
|  | .ToLocalChecked(); | 
|  | } | 
|  |  | 
|  | v8::Local<v8::String> NewStringHelper(v8::Isolate* pIsolate, | 
|  | WideStringView str) { | 
|  | return NewStringHelper(pIsolate, FX_UTF8Encode(str).AsStringView()); | 
|  | } | 
|  |  | 
|  | v8::Local<v8::Array> NewArrayHelper(v8::Isolate* pIsolate) { | 
|  | return v8::Array::New(pIsolate); | 
|  | } | 
|  |  | 
|  | v8::Local<v8::Array> NewArrayHelper(v8::Isolate* pIsolate, | 
|  | pdfium::span<v8::Local<v8::Value>> values) { | 
|  | v8::Local<v8::Array> result = NewArrayHelper(pIsolate); | 
|  | for (size_t i = 0; i < values.size(); ++i) { | 
|  | fxv8::ReentrantPutArrayElementHelper( | 
|  | pIsolate, result, i, | 
|  | values[i].IsEmpty() ? fxv8::NewUndefinedHelper(pIsolate) : values[i]); | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | v8::Local<v8::Object> NewObjectHelper(v8::Isolate* pIsolate) { | 
|  | return v8::Object::New(pIsolate); | 
|  | } | 
|  |  | 
|  | v8::Local<v8::Date> NewDateHelper(v8::Isolate* pIsolate, double d) { | 
|  | return v8::Date::New(pIsolate->GetCurrentContext(), d) | 
|  | .ToLocalChecked() | 
|  | .As<v8::Date>(); | 
|  | } | 
|  |  | 
|  | int ReentrantToInt32Helper(v8::Isolate* pIsolate, v8::Local<v8::Value> pValue) { | 
|  | if (pValue.IsEmpty()) | 
|  | return 0; | 
|  | v8::TryCatch squash_exceptions(pIsolate); | 
|  | return pValue->Int32Value(pIsolate->GetCurrentContext()).FromMaybe(0); | 
|  | } | 
|  |  | 
|  | bool ReentrantToBooleanHelper(v8::Isolate* pIsolate, | 
|  | v8::Local<v8::Value> pValue) { | 
|  | if (pValue.IsEmpty()) | 
|  | return false; | 
|  | v8::TryCatch squash_exceptions(pIsolate); | 
|  | return pValue->BooleanValue(pIsolate); | 
|  | } | 
|  |  | 
|  | float ReentrantToFloatHelper(v8::Isolate* pIsolate, | 
|  | v8::Local<v8::Value> pValue) { | 
|  | return static_cast<float>(ReentrantToDoubleHelper(pIsolate, pValue)); | 
|  | } | 
|  |  | 
|  | double ReentrantToDoubleHelper(v8::Isolate* pIsolate, | 
|  | v8::Local<v8::Value> pValue) { | 
|  | if (pValue.IsEmpty()) | 
|  | return 0.0; | 
|  | v8::TryCatch squash_exceptions(pIsolate); | 
|  | return pValue->NumberValue(pIsolate->GetCurrentContext()).FromMaybe(0.0); | 
|  | } | 
|  |  | 
|  | WideString ReentrantToWideStringHelper(v8::Isolate* pIsolate, | 
|  | v8::Local<v8::Value> pValue) { | 
|  | if (pValue.IsEmpty()) | 
|  | return WideString(); | 
|  |  | 
|  | v8::TryCatch squash_exceptions(pIsolate); | 
|  | v8::MaybeLocal<v8::String> maybe_string = | 
|  | pValue->ToString(pIsolate->GetCurrentContext()); | 
|  | if (maybe_string.IsEmpty()) | 
|  | return WideString(); | 
|  |  | 
|  | v8::String::Utf8Value s(pIsolate, maybe_string.ToLocalChecked()); | 
|  | return WideString::FromUTF8(ByteStringView(*s, s.length())); | 
|  | } | 
|  |  | 
|  | ByteString ReentrantToByteStringHelper(v8::Isolate* pIsolate, | 
|  | v8::Local<v8::Value> pValue) { | 
|  | if (pValue.IsEmpty()) | 
|  | return ByteString(); | 
|  |  | 
|  | v8::TryCatch squash_exceptions(pIsolate); | 
|  | v8::MaybeLocal<v8::String> maybe_string = | 
|  | pValue->ToString(pIsolate->GetCurrentContext()); | 
|  | if (maybe_string.IsEmpty()) | 
|  | return ByteString(); | 
|  |  | 
|  | v8::String::Utf8Value s(pIsolate, maybe_string.ToLocalChecked()); | 
|  | return ByteString(*s); | 
|  | } | 
|  |  | 
|  | v8::Local<v8::Object> ReentrantToObjectHelper(v8::Isolate* pIsolate, | 
|  | v8::Local<v8::Value> pValue) { | 
|  | if (!fxv8::IsObject(pValue)) | 
|  | return v8::Local<v8::Object>(); | 
|  |  | 
|  | v8::TryCatch squash_exceptions(pIsolate); | 
|  | v8::Local<v8::Context> context = pIsolate->GetCurrentContext(); | 
|  | return pValue->ToObject(context).ToLocalChecked(); | 
|  | } | 
|  |  | 
|  | v8::Local<v8::Array> ReentrantToArrayHelper(v8::Isolate* pIsolate, | 
|  | v8::Local<v8::Value> pValue) { | 
|  | if (!fxv8::IsArray(pValue)) | 
|  | return v8::Local<v8::Array>(); | 
|  |  | 
|  | v8::TryCatch squash_exceptions(pIsolate); | 
|  | v8::Local<v8::Context> context = pIsolate->GetCurrentContext(); | 
|  | return v8::Local<v8::Array>::Cast(pValue->ToObject(context).ToLocalChecked()); | 
|  | } | 
|  |  | 
|  | v8::Local<v8::Value> ReentrantGetObjectPropertyHelper( | 
|  | v8::Isolate* pIsolate, | 
|  | v8::Local<v8::Object> pObj, | 
|  | ByteStringView bsUTF8PropertyName) { | 
|  | if (pObj.IsEmpty()) | 
|  | return v8::Local<v8::Value>(); | 
|  |  | 
|  | v8::TryCatch squash_exceptions(pIsolate); | 
|  | v8::Local<v8::Value> val; | 
|  | if (!pObj->Get(pIsolate->GetCurrentContext(), | 
|  | NewStringHelper(pIsolate, bsUTF8PropertyName)) | 
|  | .ToLocal(&val)) { | 
|  | return v8::Local<v8::Value>(); | 
|  | } | 
|  | return val; | 
|  | } | 
|  |  | 
|  | std::vector<WideString> ReentrantGetObjectPropertyNamesHelper( | 
|  | v8::Isolate* pIsolate, | 
|  | v8::Local<v8::Object> pObj) { | 
|  | if (pObj.IsEmpty()) | 
|  | return std::vector<WideString>(); | 
|  |  | 
|  | v8::TryCatch squash_exceptions(pIsolate); | 
|  | v8::Local<v8::Array> val; | 
|  | v8::Local<v8::Context> context = pIsolate->GetCurrentContext(); | 
|  | if (!pObj->GetPropertyNames(context).ToLocal(&val)) | 
|  | return std::vector<WideString>(); | 
|  |  | 
|  | std::vector<WideString> result; | 
|  | for (uint32_t i = 0; i < val->Length(); ++i) { | 
|  | result.push_back(ReentrantToWideStringHelper( | 
|  | pIsolate, val->Get(context, i).ToLocalChecked())); | 
|  | } | 
|  | return result; | 
|  | } | 
|  |  | 
|  | bool ReentrantHasObjectOwnPropertyHelper(v8::Isolate* pIsolate, | 
|  | v8::Local<v8::Object> pObj, | 
|  | ByteStringView bsUTF8PropertyName, | 
|  | bool bUseTypeGetter) { | 
|  | if (pObj.IsEmpty()) | 
|  | return false; | 
|  |  | 
|  | v8::TryCatch squash_exceptions(pIsolate); | 
|  | v8::Local<v8::Context> pContext = pIsolate->GetCurrentContext(); | 
|  | v8::Local<v8::String> hKey = | 
|  | fxv8::NewStringHelper(pIsolate, bsUTF8PropertyName); | 
|  | return pObj->HasRealNamedProperty(pContext, hKey).FromJust() || | 
|  | (bUseTypeGetter && | 
|  | pObj->HasOwnProperty(pContext, hKey).FromMaybe(false)); | 
|  | } | 
|  |  | 
|  | bool ReentrantSetObjectOwnPropertyHelper(v8::Isolate* pIsolate, | 
|  | v8::Local<v8::Object> pObj, | 
|  | ByteStringView bsUTF8PropertyName, | 
|  | v8::Local<v8::Value> pValue) { | 
|  | if (pObj.IsEmpty() || pValue.IsEmpty()) | 
|  | return false; | 
|  |  | 
|  | v8::TryCatch squash_exceptions(pIsolate); | 
|  | v8::Local<v8::String> name = NewStringHelper(pIsolate, bsUTF8PropertyName); | 
|  | return pObj->DefineOwnProperty(pIsolate->GetCurrentContext(), name, pValue) | 
|  | .FromMaybe(false); | 
|  | } | 
|  |  | 
|  | bool ReentrantPutObjectPropertyHelper(v8::Isolate* pIsolate, | 
|  | v8::Local<v8::Object> pObj, | 
|  | ByteStringView bsUTF8PropertyName, | 
|  | v8::Local<v8::Value> pPut) { | 
|  | if (pObj.IsEmpty() || pPut.IsEmpty()) | 
|  | return false; | 
|  |  | 
|  | v8::TryCatch squash_exceptions(pIsolate); | 
|  | v8::Local<v8::String> name = NewStringHelper(pIsolate, bsUTF8PropertyName); | 
|  | v8::Maybe<bool> result = pObj->Set(pIsolate->GetCurrentContext(), name, pPut); | 
|  | return result.IsJust() && result.FromJust(); | 
|  | } | 
|  |  | 
|  | void ReentrantDeleteObjectPropertyHelper(v8::Isolate* pIsolate, | 
|  | v8::Local<v8::Object> pObj, | 
|  | ByteStringView bsUTF8PropertyName) { | 
|  | v8::TryCatch squash_exceptions(pIsolate); | 
|  | pObj->Delete(pIsolate->GetCurrentContext(), | 
|  | fxv8::NewStringHelper(pIsolate, bsUTF8PropertyName)) | 
|  | .FromJust(); | 
|  | } | 
|  |  | 
|  | bool ReentrantPutArrayElementHelper(v8::Isolate* pIsolate, | 
|  | v8::Local<v8::Array> pArray, | 
|  | unsigned index, | 
|  | v8::Local<v8::Value> pValue) { | 
|  | if (pArray.IsEmpty()) | 
|  | return false; | 
|  |  | 
|  | v8::TryCatch squash_exceptions(pIsolate); | 
|  | v8::Maybe<bool> result = | 
|  | pArray->Set(pIsolate->GetCurrentContext(), index, pValue); | 
|  | return result.IsJust() && result.FromJust(); | 
|  | } | 
|  |  | 
|  | v8::Local<v8::Value> ReentrantGetArrayElementHelper(v8::Isolate* pIsolate, | 
|  | v8::Local<v8::Array> pArray, | 
|  | unsigned index) { | 
|  | if (pArray.IsEmpty()) | 
|  | return v8::Local<v8::Value>(); | 
|  |  | 
|  | v8::TryCatch squash_exceptions(pIsolate); | 
|  | v8::Local<v8::Value> val; | 
|  | if (!pArray->Get(pIsolate->GetCurrentContext(), index).ToLocal(&val)) | 
|  | return v8::Local<v8::Value>(); | 
|  | return val; | 
|  | } | 
|  |  | 
|  | unsigned GetArrayLengthHelper(v8::Local<v8::Array> pArray) { | 
|  | if (pArray.IsEmpty()) | 
|  | return 0; | 
|  | return pArray->Length(); | 
|  | } | 
|  |  | 
|  | void ThrowExceptionHelper(v8::Isolate* pIsolate, ByteStringView str) { | 
|  | pIsolate->ThrowException(NewStringHelper(pIsolate, str)); | 
|  | } | 
|  |  | 
|  | void ThrowExceptionHelper(v8::Isolate* pIsolate, WideStringView str) { | 
|  | pIsolate->ThrowException(NewStringHelper(pIsolate, str)); | 
|  | } | 
|  |  | 
|  | }  // namespace fxv8 |