// Copyright 1998-2015 Epic Games, Inc. All Rights Reserved. #include "WebBrowserPrivatePCH.h" #include "WebJSStructDeserializerBackend.h" #if WITH_CEF3 /* Internal helpers *****************************************************************************/ namespace { template ValueType GetNumeric(CefRefPtr Container, KeyType Key) { switch(Container->GetType(Key)) { case VTYPE_BOOL: return static_cast(Container->GetBool(Key)); case VTYPE_INT: return static_cast(Container->GetInt(Key)); case VTYPE_DOUBLE: return static_cast(Container->GetDouble(Key)); case VTYPE_STRING: case VTYPE_DICTIONARY: case VTYPE_LIST: case VTYPE_NULL: case VTYPE_BINARY: default: return static_cast(0); } } template void AssignTokenFromContainer(ContainerType Container, KeyType Key, EStructDeserializerBackendTokens& OutToken, FString& PropertyName, TSharedPtr& Retval) { switch (Container->GetType(Key)) { case VTYPE_NULL: case VTYPE_BOOL: case VTYPE_INT: case VTYPE_DOUBLE: case VTYPE_STRING: OutToken = EStructDeserializerBackendTokens::Property; break; case VTYPE_DICTIONARY: { CefRefPtr Dictionary = Container->GetDictionary(Key); if (Dictionary->GetType("$type") == VTYPE_STRING ) { OutToken = EStructDeserializerBackendTokens::Property; } else { TSharedPtr NewWalker(new FCefDictionaryValueWalker(Retval, Dictionary)); Retval = NewWalker->GetNextToken(OutToken, PropertyName); } break; } case VTYPE_LIST: { TSharedPtr NewWalker(new FCefListValueWalker(Retval, Container->GetList(Key))); Retval = NewWalker->GetNextToken(OutToken, PropertyName); break; } case VTYPE_BINARY: case VTYPE_INVALID: default: OutToken = EStructDeserializerBackendTokens::Error; break; } } /** * Sets the value of the given property. * * @param Property The property to set. * @param Outer The property that contains the property to be set, if any. * @param Data A pointer to the memory holding the property's data. * @param ArrayIndex The index of the element to set (if the property is an array). * @return true on success, false otherwise. * @see ClearPropertyValue */ template bool SetPropertyValue( UProperty* Property, UProperty* Outer, void* Data, int32 ArrayIndex, const PropertyType& Value ) { PropertyType* ValuePtr = nullptr; UArrayProperty* ArrayProperty = Cast(Outer); if (ArrayProperty != nullptr) { if (ArrayProperty->Inner != Property) { return false; } FScriptArrayHelper ArrayHelper(ArrayProperty, ArrayProperty->template ContainerPtrToValuePtr(Data)); int32 Index = ArrayHelper.AddValue(); ValuePtr = (PropertyType*)ArrayHelper.GetRawPtr(Index); } else { UPropertyType* TypedProperty = Cast(Property); if (TypedProperty == nullptr || ArrayIndex >= TypedProperty->ArrayDim) { return false; } ValuePtr = TypedProperty->template ContainerPtrToValuePtr(Data, ArrayIndex); } if (ValuePtr == nullptr) { return false; } *ValuePtr = Value; return true; } template bool ReadNumericProperty(UProperty* Property, UProperty* Outer, void* Data, int32 ArrayIndex, CefRefPtr Container, KeyType Key ) { typedef typename PropertyType::TCppType TCppType; if (Property->IsA()) { return SetPropertyValue(Property, Outer, Data, ArrayIndex, GetNumeric(Container, Key)); } else { return false; } } template bool ReadBoolProperty(UProperty* Property, UProperty* Outer, void* Data, int32 ArrayIndex, CefRefPtr Container, KeyType Key ) { if (Property->IsA()) { return SetPropertyValue(Property, Outer, Data, ArrayIndex, GetNumeric(Container, Key)!=0); } return false; } template bool ReadJSFunctionProperty(TSharedPtr Scripting, UProperty* Property, UProperty* Outer, void* Data, int32 ArrayIndex, CefRefPtr Container, KeyType Key ) { if (Container->GetType(Key) != VTYPE_DICTIONARY || !Property->IsA()) { return false; } CefRefPtr Dictionary = Container->GetDictionary(Key); UStructProperty* StructProperty = Cast(Property); if ( StructProperty->Struct != FWebJSFunction::StaticStruct()) { return false; } FGuid CallbackID; if (!FGuid::Parse(FString(Dictionary->GetString("$id").ToWString().c_str()), CallbackID)) { // Invalid GUID return false; } FWebJSFunction CallbackObject(Scripting, CallbackID); return SetPropertyValue(Property, Outer, Data, ArrayIndex, CallbackObject); } template bool ReadStringProperty(UProperty* Property, UProperty* Outer, void* Data, int32 ArrayIndex, CefRefPtr Container, KeyType Key ) { if (Container->GetType(Key) == VTYPE_STRING) { FString StringValue = Container->GetString(Key).ToWString().c_str(); if (Property->IsA()) { return SetPropertyValue(Property, Outer, Data, ArrayIndex, StringValue); } else if (Property->IsA()) { return SetPropertyValue(Property, Outer, Data, ArrayIndex, *StringValue); } else if (Property->IsA()) { return SetPropertyValue(Property, Outer, Data, ArrayIndex, FText::FromString(StringValue)); } else if (Property->IsA()) { UByteProperty* ByteProperty = Cast(Property); int32 Index = ByteProperty->Enum->FindEnumIndex(*StringValue); if (Index == INDEX_NONE) { return false; } return SetPropertyValue(Property, Outer, Data, ArrayIndex, (uint8)Index); } } return false; } template bool ReadProperty(TSharedPtr Scripting, UProperty* Property, UProperty* Outer, void* Data, int32 ArrayIndex, CefRefPtr Container, KeyType Key ) { return ReadBoolProperty(Property, Outer, Data, ArrayIndex, Container, Key) || ReadStringProperty(Property, Outer, Data, ArrayIndex, Container, Key) || ReadNumericProperty(Property, Outer, Data, ArrayIndex, Container, Key) || ReadNumericProperty(Property, Outer, Data, ArrayIndex, Container, Key) || ReadNumericProperty(Property, Outer, Data, ArrayIndex, Container, Key) || ReadNumericProperty(Property, Outer, Data, ArrayIndex, Container, Key) || ReadNumericProperty(Property, Outer, Data, ArrayIndex, Container, Key) || ReadNumericProperty(Property, Outer, Data, ArrayIndex, Container, Key) || ReadNumericProperty(Property, Outer, Data, ArrayIndex, Container, Key) || ReadNumericProperty(Property, Outer, Data, ArrayIndex, Container, Key) || ReadNumericProperty(Property, Outer, Data, ArrayIndex, Container, Key) || ReadNumericProperty(Property, Outer, Data, ArrayIndex, Container, Key) || ReadJSFunctionProperty(Scripting, Property, Outer, Data, ArrayIndex, Container, Key); } } TSharedPtr FCefListValueWalker::GetNextToken(EStructDeserializerBackendTokens& OutToken, FString& PropertyName) { TSharedPtr Retval = SharedThis(this); Index++; if (Index == -1) { OutToken = EStructDeserializerBackendTokens::ArrayStart; } else if ( Index < List->GetSize() ) { AssignTokenFromContainer(List, Index, OutToken, PropertyName, Retval); PropertyName = FString(); } else { OutToken = EStructDeserializerBackendTokens::ArrayEnd; Retval = Parent; } return Retval; } bool FCefListValueWalker::ReadProperty(TSharedPtr Scripting, UProperty* Property, UProperty* Outer, void* Data, int32 ArrayIndex) { return ::ReadProperty(Scripting, Property, Outer, Data, ArrayIndex, List, Index); } TSharedPtr FCefDictionaryValueWalker::GetNextToken(EStructDeserializerBackendTokens& OutToken, FString& PropertyName) { TSharedPtr Retval = SharedThis(this); Index++; if (Index == -1) { OutToken = EStructDeserializerBackendTokens::StructureStart; } else if ( Index < Keys.size() ) { AssignTokenFromContainer(Dictionary, Keys[Index], OutToken, PropertyName, Retval); PropertyName = Keys[Index].ToWString().c_str(); } else { OutToken = EStructDeserializerBackendTokens::StructureEnd; Retval = Parent; } return Retval; } bool FCefDictionaryValueWalker::ReadProperty(TSharedPtr Scripting, UProperty* Property, UProperty* Outer, void* Data, int32 ArrayIndex) { return ::ReadProperty(Scripting, Property, Outer, Data, ArrayIndex, Dictionary, Keys[Index]); } /* IStructDeserializerBackend interface *****************************************************************************/ const FString& FWebJSStructDeserializerBackend::GetCurrentPropertyName() const { return CurrentPropertyName; } FString FWebJSStructDeserializerBackend::GetDebugString() const { return CurrentPropertyName; } const FString& FWebJSStructDeserializerBackend::GetLastErrorMessage() const { return CurrentPropertyName; } bool FWebJSStructDeserializerBackend::GetNextToken( EStructDeserializerBackendTokens& OutToken ) { if (Walker.IsValid()) { Walker = Walker->GetNextToken(OutToken, CurrentPropertyName); return true; } else { return false; } } bool FWebJSStructDeserializerBackend::ReadProperty( UProperty* Property, UProperty* Outer, void* Data, int32 ArrayIndex ) { return Walker->ReadProperty(Scripting, Property, Outer, Data, ArrayIndex); } void FWebJSStructDeserializerBackend::SkipArray() { EStructDeserializerBackendTokens Token; int32 depth = 1; while (GetNextToken(Token) && depth > 0) { switch (Token) { case EStructDeserializerBackendTokens::ArrayEnd: depth --; break; case EStructDeserializerBackendTokens::ArrayStart: depth ++; break; default: break; } } } void FWebJSStructDeserializerBackend::SkipStructure() { EStructDeserializerBackendTokens Token; int32 depth = 1; while (GetNextToken(Token) && depth > 0) { switch (Token) { case EStructDeserializerBackendTokens::StructureEnd: depth --; break; case EStructDeserializerBackendTokens::StructureStart: depth ++; break; default: break; } } } #endif