Files
AncientCivil/Plugins/Puerts/Source/JsEnv/Public/V8Utils.h
T
2025-02-10 00:44:11 +08:00

321 lines
11 KiB
C++

/*
* Tencent is pleased to support the open source community by making Puerts available.
* Copyright (C) 2020 THL A29 Limited, a Tencent company. All rights reserved.
* Puerts is licensed under the BSD 3-Clause License, except for the third-party components listed in the file 'LICENSE' which may
* be subject to their corresponding license terms. This file is subject to the terms and conditions defined in file 'LICENSE',
* which is part of this source code package.
*/
#pragma once
#include <vector>
#include "CoreMinimal.h"
#include "CoreUObject.h"
#include "NamespaceDef.h"
#include "DataTransfer.h"
#include "UECompatible.h"
namespace PUERTS_NAMESPACE
{
enum ArgType
{
EArgInt32,
EArgNumber,
EArgString,
EArgExternal,
EArgFunction,
EArgObject
};
class JSENV_API FV8Utils
{
public:
FORCEINLINE static void ThrowException(v8::Isolate* Isolate, const FString& Message)
{
ThrowException(Isolate, TCHAR_TO_ANSI(*Message));
}
FORCEINLINE static void ThrowException(v8::Isolate* Isolate, const char* Message)
{
auto ExceptionStr = v8::String::NewFromUtf8(Isolate, Message, v8::NewStringType::kNormal).ToLocalChecked();
Isolate->ThrowException(v8::Exception::Error(ExceptionStr));
}
FORCEINLINE static void* GetPointer(v8::Local<v8::Context>& Context, v8::Local<v8::Value> Value, int Index = 0)
{
if (Value.IsEmpty() || !Value->IsObject() || Value->IsUndefined() || Value->IsNull())
{
return nullptr;
}
auto Object = Value->ToObject(Context).ToLocalChecked();
return GetPointerFast<void>(Object, Index);
}
FORCEINLINE static void* GetPointer(v8::Local<v8::Object> Object, int Index = 0)
{
if (Object.IsEmpty() || Object->IsUndefined() || Object->IsNull())
{
return nullptr;
}
return GetPointerFast<void>(Object, Index);
}
template <typename T>
FORCEINLINE static T* GetPointerFast(v8::Local<v8::Object> Object, int Index = 0)
{
return DataTransfer::GetPointerFast<T>(Object, Index);
}
FORCEINLINE static UObject* GetUObject(v8::Local<v8::Context>& Context, v8::Local<v8::Value> Value, int Index = 0)
{
auto UEObject = reinterpret_cast<UObject*>(GetPointer(Context, Value, Index));
return (!UEObject || (UEObject != RELEASED_UOBJECT && UEObject->IsValidLowLevelFast() && !UEObjectIsPendingKill(UEObject)))
? UEObject
: RELEASED_UOBJECT;
}
FORCEINLINE static UObject* GetUObject(v8::Local<v8::Object> Object, int Index = 0)
{
auto UEObject = reinterpret_cast<UObject*>(GetPointer(Object, Index));
return (!UEObject || (UEObject != RELEASED_UOBJECT && UEObject->IsValidLowLevelFast() && !UEObjectIsPendingKill(UEObject)))
? UEObject
: RELEASED_UOBJECT;
}
FORCEINLINE static bool IsReleasedPtr(void* Ptr)
{
return RELEASED_UOBJECT_MEMBER == Ptr;
}
FORCEINLINE static v8::Local<v8::String> InternalString(v8::Isolate* Isolate, const FString& String)
{
return ToV8String(Isolate, String);
}
FORCEINLINE static v8::Local<v8::String> InternalString(v8::Isolate* Isolate, const char* String)
{
return v8::String::NewFromUtf8(Isolate, String, v8::NewStringType::kNormal).ToLocalChecked();
}
static FString ToFString(v8::Isolate* Isolate, v8::Local<v8::Value> Value);
FORCEINLINE static FName ToFName(v8::Isolate* Isolate, v8::Local<v8::Value> Value)
{
return UTF8_TO_TCHAR(*(v8::String::Utf8Value(Isolate, Value)));
}
FORCEINLINE static v8::Local<v8::String> ToV8String(v8::Isolate* Isolate, const FString& String)
{
// return ToV8String(Isolate, TCHAR_TO_UTF8(*String));
return ToV8String(Isolate, *String);
}
FORCEINLINE static v8::Local<v8::String> ToV8String(v8::Isolate* Isolate, const FName& String)
{
const FNameEntry* Entry = String.GetComparisonNameEntry();
FString Out;
if (String.GetNumber() == NAME_NO_NUMBER_INTERNAL)
{
Out.Empty(Entry->GetNameLength());
Entry->AppendNameToString(Out);
}
else
{
Out.Empty(Entry->GetNameLength() + 6);
Entry->AppendNameToString(Out);
Out += TEXT('_');
Out.AppendInt(NAME_INTERNAL_TO_EXTERNAL(String.GetNumber()));
}
return ToV8String(Isolate, Out);
}
FORCEINLINE static v8::Local<v8::String> ToV8String(v8::Isolate* Isolate, const FText& String)
{
return ToV8String(Isolate, String.ToString());
}
static v8::Local<v8::String> ToV8String(v8::Isolate* Isolate, const TCHAR* String);
FORCEINLINE static v8::Local<v8::String> ToV8String(v8::Isolate* Isolate, const char* String)
{
return v8::String::NewFromUtf8(Isolate, String, v8::NewStringType::kNormal).ToLocalChecked();
}
static v8::Local<v8::String> ToV8StringFromFileContent(v8::Isolate* Isolate, const TArray<uint8>& FileContent)
{
const uint8* Buffer = FileContent.GetData();
auto Size = FileContent.Num();
if (Size >= 2 && !(Size & 1) && ((Buffer[0] == 0xff && Buffer[1] == 0xfe) || (Buffer[0] == 0xfe && Buffer[1] == 0xff)))
{
FString Content;
FFileHelper::BufferToString(Content, Buffer, Size);
return ToV8String(Isolate, Content);
}
else
{
if (Size >= 3 && Buffer[0] == 0xef && Buffer[1] == 0xbb && Buffer[2] == 0xbf)
{
// Skip over UTF-8 BOM if there is one
Buffer += 3;
Size -= 3;
}
return v8::String::NewFromUtf8(Isolate, (const char*) Buffer, v8::NewStringType::kNormal, Size).ToLocalChecked();
}
}
template <typename T>
FORCEINLINE static T* IsolateData(v8::Isolate* Isolate)
{
return DataTransfer::IsolateData<T>(Isolate);
}
FORCEINLINE static bool CheckArgumentLength(const v8::FunctionCallbackInfo<v8::Value>& Info, int32 Length)
{
if (Info.Length() < Length)
{
ThrowException(Info.GetIsolate(),
FString::Printf(TEXT("Bad parameters, the function expect %d, but %d provided."), Length, Info.Length()));
return false;
}
return true;
}
FORCEINLINE static FString TryCatchToString(v8::Isolate* Isolate, v8::TryCatch* TryCatch)
{
v8::Isolate::Scope IsolateScope(Isolate);
v8::HandleScope HandleScope(Isolate);
v8::String::Utf8Value Exception(Isolate, TryCatch->Exception());
FString ExceptionStr(UTF8_TO_TCHAR(*Exception));
v8::Local<v8::Message> Message = TryCatch->Message();
if (Message.IsEmpty())
{
// 如果没有提供更详细的信息,直接输出Exception
return ExceptionStr;
}
else
{
v8::Local<v8::Context> Context(Isolate->GetCurrentContext());
// 输出 (filename):(line number): (message).
v8::String::Utf8Value FileName(Isolate, Message->GetScriptResourceName());
int LineNum = Message->GetLineNumber(Context).FromJust();
FString FileNameStr(*FileName);
FString LineNumStr = FString::FromInt(LineNum);
FString FileInfoStr;
FileInfoStr.Append(FileNameStr).Append(":").Append(LineNumStr).Append(": ").Append(ExceptionStr);
FString FinalReport;
FinalReport.Append(FileInfoStr).Append("\n");
// 输出调用栈信息
v8::Local<v8::Value> StackTrace;
if (TryCatch->StackTrace(Context).ToLocal(&StackTrace))
{
v8::String::Utf8Value StackTraceVal(Isolate, StackTrace);
FString StackTraceStr(*StackTraceVal);
FinalReport.Append("\n").Append(StackTraceStr);
}
return FinalReport;
}
}
FORCEINLINE static bool CheckArgument(const v8::FunctionCallbackInfo<v8::Value>& Info, const std::vector<ArgType>& TypesExpect)
{
if (Info.Length() < TypesExpect.size())
{
ThrowException(Info.GetIsolate(), FString::Printf(TEXT("Bad parameters, the function expect %d, but %d provided."),
TypesExpect.size(), Info.Length()));
return false;
}
for (int i = 0; i < TypesExpect.size(); ++i)
{
switch (TypesExpect[i])
{
case EArgInt32:
if (!Info[i]->IsInt32())
{
ThrowException(Info.GetIsolate(), FString::Printf(TEXT("Bad parameters #%d, expect a int32."), i));
return false;
}
else
{
break;
}
case EArgNumber:
if (!Info[i]->IsNumber())
{
ThrowException(Info.GetIsolate(), FString::Printf(TEXT("Bad parameters #%d, expect a int32."), i));
return false;
}
else
{
break;
}
case EArgString:
if (!Info[i]->IsString())
{
ThrowException(Info.GetIsolate(), FString::Printf(TEXT("Bad parameters #%d, expect a string."), i));
return false;
}
else
{
break;
}
case EArgExternal:
if (!Info[i]->IsExternal())
{
ThrowException(Info.GetIsolate(), FString::Printf(TEXT("Bad parameters #%d, expect an external."), i));
return false;
}
else
{
break;
}
case EArgFunction:
if (!Info[i]->IsFunction())
{
ThrowException(Info.GetIsolate(), FString::Printf(TEXT("Bad parameters #%d, expect a function."), i));
return false;
}
else
{
break;
}
case EArgObject:
if (!Info[i]->IsObject())
{
ThrowException(Info.GetIsolate(), FString::Printf(TEXT("Bad parameters #%d, expect a object."), i));
return false;
}
else
{
break;
}
default:
break;
}
}
return true;
}
};
} // namespace PUERTS_NAMESPACE
#define CHECK_V8_ARGS_LEN(Length) \
if (!FV8Utils::CheckArgumentLength(Info, Length)) \
{ \
return; \
}
#define CHECK_V8_ARGS(...) \
static std::vector<ArgType> ArgExpect = {__VA_ARGS__}; \
if (!FV8Utils::CheckArgument(Info, ArgExpect)) \
{ \
return; \
}