| // 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" |
| |
| #include "third_party/base/numerics/safe_conversions.h" |
| #include "v8/include/v8-container.h" |
| #include "v8/include/v8-date.h" |
| #include "v8/include/v8-exception.h" |
| #include "v8/include/v8-isolate.h" |
| #include "v8/include/v8-primitive.h" |
| #include "v8/include/v8-value.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, |
| pdfium::base::checked_cast<int>(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>(); |
| } |
| |
| WideString ToWideString(v8::Isolate* pIsolate, v8::Local<v8::String> pValue) { |
| v8::String::Utf8Value s(pIsolate, pValue); |
| return WideString::FromUTF8(ByteStringView(*s, s.length())); |
| } |
| |
| ByteString ToByteString(v8::Isolate* pIsolate, v8::Local<v8::String> pValue) { |
| v8::String::Utf8Value s(pIsolate, pValue); |
| return ByteString(*s, s.length()); |
| } |
| |
| 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(); |
| |
| return ToWideString(pIsolate, maybe_string.ToLocalChecked()); |
| } |
| |
| 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(); |
| |
| return ToByteString(pIsolate, maybe_string.ToLocalChecked()); |
| } |
| |
| 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) { |
| 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(); |
| } |
| |
| 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, |
| size_t index, |
| v8::Local<v8::Value> pValue) { |
| if (pArray.IsEmpty()) |
| return false; |
| |
| v8::TryCatch squash_exceptions(pIsolate); |
| v8::Maybe<bool> result = |
| pArray->Set(pIsolate->GetCurrentContext(), |
| pdfium::base::checked_cast<uint32_t>(index), pValue); |
| return result.IsJust() && result.FromJust(); |
| } |
| |
| v8::Local<v8::Value> ReentrantGetArrayElementHelper(v8::Isolate* pIsolate, |
| v8::Local<v8::Array> pArray, |
| size_t index) { |
| if (pArray.IsEmpty()) |
| return v8::Local<v8::Value>(); |
| |
| v8::TryCatch squash_exceptions(pIsolate); |
| v8::Local<v8::Value> val; |
| if (!pArray |
| ->Get(pIsolate->GetCurrentContext(), |
| pdfium::base::checked_cast<uint32_t>(index)) |
| .ToLocal(&val)) { |
| return v8::Local<v8::Value>(); |
| } |
| return val; |
| } |
| |
| size_t 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 |