From 19f3e7e19d46c9c6c02996a2cdeec211a0b0a19b Mon Sep 17 00:00:00 2001 From: prudnikov Date: Mon, 4 Sep 2017 19:11:29 +0300 Subject: [PATCH 01/24] Custom json parser --- .../VaRestPlugin/Classes/VaRestJsonObject.h | 20 +- Source/VaRestPlugin/Classes/VaRestJsonValue.h | 1 + .../VaRestPlugin/Private/VaRestJsonObject.cpp | 177 +++- .../VaRestPlugin/Private/VaRestJsonParser.cpp | 896 ++++++++++++++++++ .../VaRestPlugin/Private/VaRestJsonParser.h | 190 ++++ .../Private/VaRestRequestJSON.cpp | 21 +- 6 files changed, 1294 insertions(+), 11 deletions(-) create mode 100644 Source/VaRestPlugin/Private/VaRestJsonParser.cpp create mode 100644 Source/VaRestPlugin/Private/VaRestJsonParser.h diff --git a/Source/VaRestPlugin/Classes/VaRestJsonObject.h b/Source/VaRestPlugin/Classes/VaRestJsonObject.h index 4d417f87..09f39333 100644 --- a/Source/VaRestPlugin/Classes/VaRestJsonObject.h +++ b/Source/VaRestPlugin/Classes/VaRestJsonObject.h @@ -6,6 +6,7 @@ #include "VaRestJsonObject.generated.h" class UVaRestJsonValue; +class FJsonObject; /** * Blueprintable FJsonObject wrapper @@ -165,7 +166,24 @@ class VARESTPLUGIN_API UVaRestJsonObject : public UObject UFUNCTION(BlueprintCallable, Category = "VaRest|Json") void SetObjectArrayField(const FString& FieldName, const TArray& ObjectArray); - + ////////////////////////////////////////////////////////////////////////// + // Deserialize + + /** Deserialize byte content to json */ + void DeserializeFromUTF8Bytes(const ANSICHAR* Bytes, int32 Size); + + /** Deserialize byte content to json */ + void DeserializeFromTCHARBytes(const TCHAR* Bytes, int32 Size); + +public: + /** Deserialize byte stream from reader */ + void DecodeFromArchive(TUniquePtr& Reader); + + /** Save json to file */ + bool WriteToFile(const FString& Path); + + static bool WriteStringToArchive(FArchive& Ar, const TCHAR* StrPtr, int64 Len); + ////////////////////////////////////////////////////////////////////////// // Data diff --git a/Source/VaRestPlugin/Classes/VaRestJsonValue.h b/Source/VaRestPlugin/Classes/VaRestJsonValue.h index f13e4564..4b7ad64f 100644 --- a/Source/VaRestPlugin/Classes/VaRestJsonValue.h +++ b/Source/VaRestPlugin/Classes/VaRestJsonValue.h @@ -6,6 +6,7 @@ #include "VaRestJsonValue.generated.h" class UVaRestJsonObject; +class FJsonValue; /** * Represents all the types a Json Value can be. diff --git a/Source/VaRestPlugin/Private/VaRestJsonObject.cpp b/Source/VaRestPlugin/Private/VaRestJsonObject.cpp index c8b99a04..654e6893 100644 --- a/Source/VaRestPlugin/Private/VaRestJsonObject.cpp +++ b/Source/VaRestPlugin/Private/VaRestJsonObject.cpp @@ -1,6 +1,7 @@ // Copyright 2014 Vladimir Alyamkin. All Rights Reserved. #include "VaRestPluginPrivatePCH.h" +#include "VaRestJsonParser.h" typedef TJsonWriterFactory< TCHAR, TCondensedJsonPrintPolicy > FCondensedJsonStringWriterFactory; typedef TJsonWriter< TCHAR, TCondensedJsonPrintPolicy > FCondensedJsonStringWriter; @@ -69,8 +70,9 @@ FString UVaRestJsonObject::EncodeJsonToSingleString() const bool UVaRestJsonObject::DecodeJson(const FString& JsonString) { - TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create(*JsonString); - if (FJsonSerializer::Deserialize(Reader, JsonObj) && JsonObj.IsValid()) + DeserializeFromTCHARBytes(JsonString.GetCharArray().GetData(), JsonString.Len()); + + if (JsonObj.IsValid()) { return true; } @@ -539,3 +541,174 @@ void UVaRestJsonObject::SetObjectArrayField(const FString& FieldName, const TArr JsonObj->SetArrayField(FieldName, EntriesArray); } + +////////////////////////////////////////////////////////////////////////// +// Deserialize + +void UVaRestJsonObject::DeserializeFromUTF8Bytes(const ANSICHAR* Bytes, int32 Size) +{ + FJSONReader Reader; + + const ANSICHAR* EndByte = Bytes + Size; + while (Bytes < EndByte) + { + TCHAR Char = FUTF8ToTCHAR_Convert::utf8codepoint(&Bytes); + + if (Char > 0xFFFF) + { + Char = UNICODE_BOGUS_CHAR_CODEPOINT; + } + + if (!Reader.Read(Char)) + { + break; + } + } + + SetRootObject(Reader.State.Root); +} + +void UVaRestJsonObject::DeserializeFromTCHARBytes(const TCHAR* Bytes, int32 Size) +{ + FJSONReader Reader; + + int32 i = 0; + while (i < Size) + { + if (!Reader.Read(Bytes[i++])) + { + break; + } + } + + SetRootObject(Reader.State.Root); +} + +void UVaRestJsonObject::DecodeFromArchive(TUniquePtr& Reader) +{ + FArchive& Ar = (*Reader.Get()); + uint8 SymbolBytes[2]; + + // Read first two bytes + Ar << SymbolBytes[0]; + Ar << SymbolBytes[1]; + + bool bIsIntelByteOrder = true; + + if(SymbolBytes[0] == 0xff && SymbolBytes[1] == 0xfe) + { + // Unicode Intel byte order. Less 1 for the FFFE header, additional 1 for null terminator. + bIsIntelByteOrder = true; + } + else if(SymbolBytes[0] == 0xfe && SymbolBytes[1] == 0xff) + { + // Unicode non-Intel byte order. Less 1 for the FFFE header, additional 1 for null terminator. + bIsIntelByteOrder = false; + } + + FJSONReader JsonReader; + TCHAR Char; + + while (!Ar.AtEnd()) + { + Ar << SymbolBytes[0]; + + if (Ar.AtEnd()) + { + break; + } + + Ar << SymbolBytes[1]; + + if (bIsIntelByteOrder) + { + Char = CharCast((UCS2CHAR)((uint16)SymbolBytes[0] + (uint16)SymbolBytes[1] * 256)); + } + else + { + Char = CharCast((UCS2CHAR)((uint16)SymbolBytes[1] + (uint16)SymbolBytes[0] * 256)); + } + + if (!JsonReader.Read(Char)) + { + break; + } + } + + SetRootObject(JsonReader.State.Root); + + if (!Ar.Close()) + { + UE_LOG(LogVaRest, Error, TEXT("UVaRestJsonObject::DecodeFromArchive: Error! Can't close file!")); + } + +} + +bool UVaRestJsonObject::WriteToFile(const FString& Path) +{ + if (JsonObj.IsValid()) + { + TUniquePtr FileWriter(IFileManager::Get().CreateFileWriter(*Path)); + if (!FileWriter) + { + return false; + } + + FArchive& Ar = *FileWriter.Get(); + + UCS2CHAR BOM = UNICODE_BOM; + Ar.Serialize( &BOM, sizeof(UCS2CHAR) ); + + FString Str = FString(TEXT("{")); + WriteStringToArchive(Ar, *Str, Str.Len()); + + int32 ElementCount = 0; + FJSONWriter JsonWriter; + for (auto JsonObjectValuePair : JsonObj->Values) + { + Str = FString(TEXT("\"")); + WriteStringToArchive(Ar, *Str, Str.Len()); + + const TCHAR* BufferPtr = *JsonObjectValuePair.Key; + for (int i = 0; i < JsonObjectValuePair.Key.Len(); ++i) + { + Str = FString(1, &BufferPtr[i]); +#if PLATFORM_WINDOWS + WriteStringToArchive(Ar, *Str, Str.Len() - 1); +#else + WriteStringToArchive(Ar, *Str, Str.Len()); +#endif + } + + Str = FString(TEXT("\"")); + WriteStringToArchive(Ar, *Str, Str.Len()); + + Str = FString(TEXT(":")); + WriteStringToArchive(Ar, *Str, Str.Len()); + + ++ElementCount; + + JsonWriter.Write(JsonObjectValuePair.Value, FileWriter.Get(), ElementCount >= JsonObj->Values.Num()); + } + + Str = FString(TEXT("}")); + WriteStringToArchive(Ar, *Str, Str.Len()); + + FileWriter->Close(); + + return true; + } + else + { + UE_LOG(LogVaRest, Error, TEXT("UVaRestJsonObject::WriteToFile: Root object is invalid!")); + return false; + } +} + +bool UVaRestJsonObject::WriteStringToArchive( FArchive& Ar, const TCHAR* StrPtr, int64 Len) +{ + auto Src = StringCast(StrPtr, Len); + Ar.Serialize( (UCS2CHAR*)Src.Get(), Src.Length() * sizeof(UCS2CHAR) ); + + return true; +} diff --git a/Source/VaRestPlugin/Private/VaRestJsonParser.cpp b/Source/VaRestPlugin/Private/VaRestJsonParser.cpp new file mode 100644 index 00000000..755ada3a --- /dev/null +++ b/Source/VaRestPlugin/Private/VaRestJsonParser.cpp @@ -0,0 +1,896 @@ +// Copyright 2015-2017 Mail.Ru Group. All Rights Reserved. + +#include "VaRestPluginPrivatePCH.h" +#include "VaRestJsonParser.h" +#include "VaRestJsonObject.h" +#include "Dom/JsonObject.h" +#include "Dom/JsonValue.h" +#include "LogMacros.h" + +FJSONState::FJSONState() +: Notation(EJSONNotation::NONE) +, bEscape(false) +, bError(false) +, Quote(UNICODE_BOGUS_CHAR_CODEPOINT) +{ + Key.Reserve(1024); + Data.Reserve(4096); + + Root = TSharedPtr(nullptr); + + Objects.Reserve(64); + Tokens.Reserve(64); + + Tokens.Add(EJSONToken::ROOT); +} + +EJSONToken FJSONState::GetToken(int32 Index) +{ + return Tokens.Num() > Index ? Tokens.Last(Index) : EJSONToken::ERROR; +} + +bool FJSONState::CheckTokens(EJSONToken T1) +{ + return T1 == GetToken(0); +} + +bool FJSONState::CheckTokens(EJSONToken T1, EJSONToken T2) +{ + return T1 == GetToken(1) && T2 == GetToken(0); +} + +bool FJSONState::CheckTokens(EJSONToken T1, EJSONToken T2, EJSONToken T3) +{ + return T1 == GetToken(2) && T2 == GetToken(1) && T3 == GetToken(0); +} + +void FJSONState::PopToken(int32 Num) +{ + if (Num > 0) + { + if (Tokens.Num() >= Num) + { + Tokens.RemoveAt(Tokens.Num() - Num, Num, false); + } + else + { + bError = true; + } + } + + Notation = EJSONNotation::NONE; +} + +void FJSONState::PopObject() +{ + if (Objects.Num() > 0) + { + auto Object = Objects.Pop(false); + if (Object->Type == EJson::Object) + { + return; + } + } + + bError = true; +} + +void FJSONState::PopArray() +{ + if (Objects.Num() > 0) + { + auto Object = Objects.Pop(false); + if (Object->Type == EJson::Array) + { + return; + } + } + + bError = true; +} + +void FJSONState::PopValue(bool bCheckType) +{ + if (Objects.Num() > 0) + { + auto Value = Objects.Last(0); + if (Value->Type == EJson::Object || Value->Type == EJson::Array) + { + if (bCheckType) + { + bError = true; + } + } + else + { + Objects.Pop(false); + if (Objects.Num() > 0) + { + switch(Value->Type) + { + case EJson::Null: + { + auto LowerCase = Data.ToLower(); + if (LowerCase != TEXT("null")) + { + bError = true; + } + break; + } + case EJson::String: + { + ((FJsonValueNonConstString*) Value.Get())->AsNonConstString() = Data; + break; + } + case EJson::Number: + { + auto LowerCase = Data.ToLower(); + if (LowerCase.IsNumeric()) + { + ((FJsonValueNonConstNumber*) Value.Get())->AsNonConstNumber() = FCString::Atod(*LowerCase); + } + else + { + bError = true; + } + break; + } + case EJson::Boolean: + { + auto LowerCase = Data.ToLower(); + if (LowerCase == TEXT("true")) + { + ((FJsonValueNonConstBoolean*) Value.Get())->AsNonConstBool() = true; + } + else if (LowerCase == TEXT("false")) + { + ((FJsonValueNonConstBoolean*) Value.Get())->AsNonConstBool() = false; + } + else + { + bError = true; + } + break; + } + default: + { + bError = true; + return; + } + } + + ClearData(); + + auto Container = Objects.Last(0); + if (Container->Type == EJson::Object) + { + if (Key.Len() > 0) + { + Container->AsObject()->SetField(Key, Value); + ClearKey(); + } + else + { + bError = true; + } + } + else if (Container->Type == EJson::Array) + { + ((FJsonValueNonConstArray*) Container.Get())->AsNonConstArray().Add(Value); + } + else + { + bError = true; + } + } + else + { + bError = true; + } + } + } + else + { + bError = true; + } +} + +FJsonValue* FJSONState::GetLast() +{ + if (Objects.Num() > 0) + { + return Objects.Last(0).Get(); + } + bError = true; + return nullptr; +} + +FJsonValueObject* FJSONState::GetObject() +{ + FJsonValue* Value = GetLast(); + if (Value != nullptr && Value->Type == EJson::Object) + { + return (FJsonValueObject*) Value; + } + bError = true; + return nullptr; +} + +FJsonValueNonConstArray* FJSONState::GetArray() +{ + FJsonValue* Value = GetLast(); + if (Value != nullptr && Value->Type == EJson::Array) + { + return (FJsonValueNonConstArray*) Value; + } + bError = true; + return nullptr; +} + +TSharedPtr FJSONState::PushObject() +{ + TSharedPtr Result(new FJsonValueObject(TSharedPtr(new FJsonObject()))); + Objects.Add(Result); + return Result; +} + +TSharedPtr FJSONState::PushObject(TSharedPtr Object) +{ + TSharedPtr Result(new FJsonValueObject(Object)); + Objects.Add(Result); + return Result; +} + +TSharedPtr FJSONState::PushArray() +{ + TArray> Empty; + TSharedPtr Result(new FJsonValueNonConstArray(Empty)); + Objects.Add(Result); + return Result; +} + +TSharedPtr FJSONState::PushBoolean() +{ + TSharedPtr Result(new FJsonValueNonConstBoolean(false)); + Objects.Add(Result); + return Result; +} + +TSharedPtr FJSONState::PushNull() +{ + TSharedPtr Result(new FJsonValueNull()); + Objects.Add(Result); + return Result; +} + +TSharedPtr FJSONState::PushNumber() +{ + TSharedPtr Result(new FJsonValueNonConstNumber(0.f)); + Objects.Add(Result); + return Result; +} + +TSharedPtr FJSONState::PushString() +{ + TSharedPtr Result(new FJsonValueNonConstString(TEXT(""))); + Objects.Add(Result); + return Result; +} + +void FJSONState::ClearData() +{ + Data.Empty(Data.GetCharArray().Max()); +} + +void FJSONState::ClearKey() +{ + Key.Empty(Key.GetCharArray().Max()); +} + +void FJSONState::DataToKey() +{ + ClearKey(); + Key += Data; + ClearData(); +} + +void FJSONState::Error() +{ + bError = true; +} + +FJSONReader::FJSONReader() +{ + +} + +bool FJSONReader::IsNewLine(const TCHAR& Char) +{ + return Char == '\n'; +} + +bool FJSONReader::IsSpace(const TCHAR& Char) +{ + return IsNewLine(Char) || Char == ' ' || Char == '\t' || Char == '\r'; +} + +bool FJSONReader::FindToken(const TCHAR& Char) +{ + if (State.bEscape) + { + return false; + } + + if (State.Notation != EJSONNotation::STRING) + { + switch(Char) + { + case '{': State.Tokens.Add(EJSONToken::CURLY_BEGIN); return true; + case '}': State.Tokens.Add(EJSONToken::CURLY_END); return true; + case '[': State.Tokens.Add(EJSONToken::SQUARE_BEGIN); return true; + case ']': State.Tokens.Add(EJSONToken::SQUARE_END); return true; + case ',': State.Tokens.Add(EJSONToken::COMMA); return true; + case ':': State.Tokens.Add(EJSONToken::COLON); return true; + } + } + return false; +} + +void FJSONReader::UpdateNotation() +{ + switch(State.GetToken()) + { + case EJSONToken::ROOT: + { + return; + } + case EJSONToken::CURLY_BEGIN: + { + if (State.CheckTokens(EJSONToken::SQUARE_BEGIN, EJSONToken::CURLY_BEGIN)) // Object in array "[{" + { + State.Notation = EJSONNotation::OBJECT; + auto Value = State.GetArray(); + if (Value != nullptr) + { + Value->AsNonConstArray().Add(State.PushObject()); + } + else + { + State.Error(); + } + } + else if (State.CheckTokens(EJSONToken::CURLY_BEGIN, EJSONToken::COLON, EJSONToken::CURLY_BEGIN)) // Object in key "{:{" + { + if (State.Key.Len() > 0) + { + State.Notation = EJSONNotation::OBJECT; + auto Value = State.GetObject(); + if (Value != nullptr) + { + Value->AsObject()->SetField(State.Key, State.PushObject()); + State.ClearKey(); + } + else + { + State.Error(); + } + } + else + { + State.Error(); + } + } + else if (State.CheckTokens(EJSONToken::ROOT, EJSONToken::CURLY_BEGIN)) // Root object "{" + { + if (State.Root.IsValid()) + { + State.Error(); + } + else + { + State.Root = TSharedPtr(new FJsonObject()); + State.PushObject(State.Root); // add root object + State.Notation = EJSONNotation::OBJECT; + } + } + else + { + State.Error(); + } + break; + } + case EJSONToken::CURLY_END: + { + if (State.CheckTokens(EJSONToken::CURLY_BEGIN, EJSONToken::CURLY_END)) // Close object "{}" + { + State.PopToken(2); // pop "{}" + State.PopObject(); // remove object + } + else if (State.CheckTokens(EJSONToken::CURLY_BEGIN, EJSONToken::COLON, EJSONToken::CURLY_END)) // Close object "{:}" + { + State.PopToken(3); // pop "{:}" + State.PopValue(); // remove value + State.PopObject(); // remove object + } + else + { + State.Error(); + } + + if (State.CheckTokens(EJSONToken::COLON)) // Object in object ":" + { + State.PopToken(1); // pop ":" + } + + State.Notation = EJSONNotation::SKIP; + + break; + } + case EJSONToken::SQUARE_BEGIN: + { + if (State.CheckTokens(EJSONToken::SQUARE_BEGIN, EJSONToken::SQUARE_BEGIN)) // Array in array "[[" + { + State.Notation = EJSONNotation::ARRAY; + auto Value = State.GetArray(); + if (Value != nullptr) + { + Value->AsNonConstArray().Add(State.PushArray()); + } + else + { + State.Error(); + } + } + else if (State.CheckTokens(EJSONToken::CURLY_BEGIN, EJSONToken::COLON, EJSONToken::SQUARE_BEGIN)) // Array in key "{:[" + { + State.Notation = EJSONNotation::ARRAY; + if (State.Key.Len() > 0) + { + auto Value = State.GetObject(); + if (Value != nullptr) + { + Value->AsObject()->SetField(State.Key, State.PushArray()); + State.ClearKey(); + } + else + { + State.Error(); + } + } + else + { + State.Error(); + } + } + else if (State.CheckTokens(EJSONToken::ROOT, EJSONToken::SQUARE_BEGIN)) // Root array "{" + { + State.Error(); // Not support + } + else + { + State.Error(); + } + break; + } + case EJSONToken::SQUARE_END: + { + if (State.CheckTokens(EJSONToken::SQUARE_BEGIN, EJSONToken::SQUARE_END)) // Close array "[]" + { + State.PopToken(2); // remove token "[]" + State.PopValue(false); // remove value if exists + State.PopArray(); // remove array + + if (State.CheckTokens(EJSONToken::COLON)) // Array in object ":" + { + State.PopToken(1); // pop ":" + } + } + else + { + State.Error(); + } + + State.Notation = EJSONNotation::SKIP; + + break; + } + case EJSONToken::COMMA: + { + if (State.CheckTokens(EJSONToken::CURLY_BEGIN, EJSONToken::COLON, EJSONToken::COMMA)) // Next record in object "{:," + { + State.PopToken(2); // remove token ":," + State.PopValue(false); // remove value + State.Notation = EJSONNotation::OBJECT; + } + else if (State.CheckTokens(EJSONToken::CURLY_BEGIN, EJSONToken::COMMA)) // Next record in object "{," + { + State.PopToken(1); // remove token "," + State.Notation = EJSONNotation::OBJECT; + } + else if (State.CheckTokens(EJSONToken::SQUARE_BEGIN, EJSONToken::COMMA)) // Next record in array "[," + { + State.PopToken(1); // remove token "," + State.PopValue(false); // remove value + State.Notation = EJSONNotation::ARRAY; + } + else + { + State.Error(); + } + break; + } + case EJSONToken::COLON: + { + if (State.CheckTokens(EJSONToken::CURLY_BEGIN, EJSONToken::COLON)) // Object key close "{:" + { + State.Notation = EJSONNotation::OBJECT; + if (State.Data.Len() > 0) + { + State.DataToKey(); + } + else + { + State.Error(); + } + } + else + { + State.Error(); + } + break; + } + case EJSONToken::ERROR: + { + State.Error(); + break; + } + } + + if (!State.bError && State.Notation == EJSONNotation::NONE) + { + UpdateNotation(); + } +} + +void FJSONReader::ReadAsString(const TCHAR& Char) +{ + if (IsNewLine(Char)) + { + State.Error(); + return; + } + + if (!State.bEscape && State.Quote == Char) + { + State.Quote = UNICODE_BOGUS_CHAR_CODEPOINT; + State.Notation = EJSONNotation::SKIP; + } + else + { + if (State.bEscape) + { + switch(Char) + { + case 'n': State.Data.AppendChar('\n'); break; + case 't': State.Data.AppendChar('\t'); break; + default: State.Data.AppendChar(Char); break; + } + } + else + { + State.Data.AppendChar(Char); + } + } +} + +void FJSONReader::ReadAsStringSpecial(const TCHAR& Char) +{ + if (IsSpace(Char) && State.Data.Len() > 0) + { + State.Notation = EJSONNotation::SKIP; + return; + } + + State.Data.AppendChar(Char); +} + +void FJSONReader::ReadAsNumber(const TCHAR& Char) +{ + if (IsSpace(Char) && State.Data.Len() > 0) + { + State.Notation = EJSONNotation::SKIP; + return; + } + + if ((Char >= '0' && Char <= '9') || Char == '-' || Char == '.' || Char == '+' || Char == 'e' || Char == 'E') + { + State.Data.AppendChar(Char); + } + else + { + State.Error(); + } +} + +void FJSONReader::ReadBasicValue(const TCHAR& Char) +{ + switch(Char) + { + case 'T': + case 't': + case 'F': + case 'f': + { + State.PushBoolean(); + State.Notation = EJSONNotation::STRING_SPECIAL; + ReadAsStringSpecial(Char); + return; + } + case 'N': + case 'n': + { + State.PushNull(); + State.Notation = EJSONNotation::STRING_SPECIAL; + ReadAsStringSpecial(Char); + return; + } + case '\'': + case '"': + { + State.PushString(); + State.Notation = EJSONNotation::STRING; + State.Quote = Char; + return; + } + } + + if ((Char >= '0' && Char <= '9') || Char == '-') + { + State.PushNumber(); + State.Notation = EJSONNotation::NUMBER; + ReadAsNumber(Char); + return; + } +} + +void FJSONReader::ReadAsArray(const TCHAR& Char) +{ + if (IsSpace(Char)) + { + return; + } + ReadBasicValue(Char); +} + +void FJSONReader::ReadAsObject(const TCHAR& Char) +{ + if (IsSpace(Char)) + { + return; + } + + if (State.CheckTokens(EJSONToken::CURLY_BEGIN)) // read key "{" + { + if (Char == '\'' || Char == '"') + { + State.Notation = EJSONNotation::STRING; + State.Quote = Char; + } + else + { + State.Notation = EJSONNotation::STRING_SPECIAL; + ReadAsStringSpecial(Char); + } + } + else if (State.CheckTokens(EJSONToken::CURLY_BEGIN, EJSONToken::COLON)) // read value "{:" + { + ReadBasicValue(Char); + } +} + +void FJSONReader::Skip(const TCHAR& Char) +{ + if (!IsSpace(Char)) + { + State.Error(); + } +} + +bool FJSONReader::Read(const TCHAR Char) +{ + if (Char == '\\' && !State.bEscape) + { + State.bEscape = true; + return true; + } + + if (FindToken(Char)) + { + State.Notation = EJSONNotation::NONE; + UpdateNotation(); + return true; + } + + switch(State.Notation) + { + case EJSONNotation::NONE: UpdateNotation(); break; + + case EJSONNotation::STRING: ReadAsString(Char); break; + case EJSONNotation::STRING_SPECIAL: ReadAsStringSpecial(Char); break; + case EJSONNotation::NUMBER: ReadAsNumber(Char); break; + case EJSONNotation::ARRAY: ReadAsArray(Char); break; + case EJSONNotation::OBJECT: ReadAsObject(Char); break; + + case EJSONNotation::SKIP: Skip(Char); break; + } + + if (State.bError) + { + State.Root = TSharedPtr(nullptr); + return false; + } + + State.bEscape = false; + + return true; +} + +FJSONWriter::FJSONWriter() +{ + +} + +bool FJSONWriter::GetStartChar(const TSharedPtr& JsonValue, FString& Str) +{ + switch (JsonValue->Type) + { + case EJson::Object: + Str = FString(TEXT("{")); + break; + case EJson::Array: + Str = FString(TEXT("[")); + break; + case EJson::String: + Str = FString(TEXT("\"")); + break; + default: + return false; + break; + } + + return true; +} + +bool FJSONWriter::GetEndChar(const TSharedPtr& JsonValue, FString& Str) +{ + switch (JsonValue->Type) + { + case EJson::Object: + Str = FString(TEXT("}")); + break; + case EJson::Array: + Str = FString(TEXT("]")); + break; + case EJson::String: + Str = FString(TEXT("\"")); + break; + default: + return false; + break; + } + + return true; +} + +void FJSONWriter::Write(TSharedPtr JsonValue, FArchive* Writer, bool IsLastElement) +{ + FString Str; + FArchive& Ar = *Writer; + + if (GetStartChar(JsonValue, Str)) + { + UVaRestJsonObject::WriteStringToArchive(Ar, *Str, Str.Len()); + } + + switch (JsonValue->Type) + { + case EJson::Object: + { + int ElementsCount = 0; + auto Values = JsonValue->AsObject()->Values; + + for (auto& ChildJsonPair : Values) + { + Str = FString(TEXT("\"")); + UVaRestJsonObject::WriteStringToArchive(Ar, *Str, Str.Len()); + + const TCHAR* BufferPtr = *ChildJsonPair.Key; + for (int i = 0; i < ChildJsonPair.Key.Len(); ++i) + { + Str = FString(1, &ChildJsonPair.Key[i]); +#if PLATFORM_WINDOWS + UVaRestJsonObject::WriteStringToArchive(Ar, *Str, Str.Len() - 1); +#else + UVaRestJsonObject::WriteStringToArchive(Ar, *Str, Str.Len()); +#endif + } + + Str = FString(TEXT("\"")); + UVaRestJsonObject::WriteStringToArchive(Ar, *Str, Str.Len()); + + Str = FString(TEXT(":")); + UVaRestJsonObject::WriteStringToArchive(Ar, *Str, Str.Len()); + + ++ElementsCount; + + Write(ChildJsonPair.Value, Writer, ElementsCount >= Values.Num()); + } + break; + } + case EJson::Array: + { + int ElementsCount = 0; + auto Array = JsonValue->AsArray(); + + for (auto& ChildJsonValue : Array) + { + ++ElementsCount; + Write(ChildJsonValue, Writer, ElementsCount >= Array.Num()); + } + break; + } + default: + { + FString Value = JsonValue->AsString(); + + const TCHAR* BufferPtr = *Value; + for (int i = 0; i < Value.Len(); ++i) + { + Str = FString(1, &BufferPtr[i]); + if (Str == TEXT("\"")) + { + Str = FString(TEXT("\\")); + UVaRestJsonObject::WriteStringToArchive(Ar, *Str, Str.Len()); + Str = FString(1, &BufferPtr[i]); + } + if (Str == TEXT("\n")) + { + Str = FString(TEXT("\\")); + UVaRestJsonObject::WriteStringToArchive(Ar, *Str, Str.Len()); + Str = FString(TEXT("n")); + UVaRestJsonObject::WriteStringToArchive(Ar, *Str, Str.Len()); + Str = FString(1, &BufferPtr[i]); + } + else if (Str == TEXT("\t")) + { + Str = FString(TEXT("\\")); + UVaRestJsonObject::WriteStringToArchive(Ar, *Str, Str.Len()); + Str = FString(TEXT("t")); + UVaRestJsonObject::WriteStringToArchive(Ar, *Str, Str.Len()); + Str = FString(1, &BufferPtr[i]); + } + else + { +#if PLATFORM_WINDOWS + UVaRestJsonObject::WriteStringToArchive(Ar, *Str, Str.Len() - 1); +#else + UVaRestJsonObject::WriteStringToArchive(Ar, *Str, Str.Len()); +#endif + } + } + + break; + } + } + + if (GetEndChar(JsonValue, Str)) + { + UVaRestJsonObject::WriteStringToArchive(Ar, *Str, Str.Len()); + } + + if (!IsLastElement) + { + Str = FString(TEXT(",")); + UVaRestJsonObject::WriteStringToArchive(Ar, *Str, Str.Len()); + } +} diff --git a/Source/VaRestPlugin/Private/VaRestJsonParser.h b/Source/VaRestPlugin/Private/VaRestJsonParser.h new file mode 100644 index 00000000..9a9ef42c --- /dev/null +++ b/Source/VaRestPlugin/Private/VaRestJsonParser.h @@ -0,0 +1,190 @@ +// Copyright 2015-2017 Mail.Ru Group. All Rights Reserved. + +#pragma once + +class FJsonValueNonConstArray : public FJsonValueArray +{ +public: + FJsonValueNonConstArray(const TArray>& InArray) : FJsonValueArray(InArray) {} + + /** return non const array */ + TArray>& AsNonConstArray() { return Value; } +}; + +class FJsonValueNonConstBoolean : public FJsonValueBoolean +{ +public: + FJsonValueNonConstBoolean(bool InBool) : FJsonValueBoolean(InBool) {} + + /** return non const bool */ + bool& AsNonConstBool() { return Value; } +}; + +class FJsonValueNonConstString : public FJsonValueString +{ +public: + FJsonValueNonConstString(const FString& InString) : FJsonValueString(InString) {} + + /** return non const string */ + FString& AsNonConstString() { return Value; } +}; + +class FJsonValueNonConstNumber : public FJsonValueNumber +{ +public: + FJsonValueNonConstNumber(double InNumber) : FJsonValueNumber(InNumber) {} + + /** return non const number */ + double& AsNonConstNumber() { return Value; } +}; + +enum class EJSONNotation +{ + NONE, + STRING, + STRING_SPECIAL, + SKIP, + NUMBER, + ARRAY, + OBJECT, +}; + +enum class EJSONToken +{ + CURLY_BEGIN, + CURLY_END, + SQUARE_BEGIN, + SQUARE_END, + COMMA, + COLON, + ROOT, + ERROR, +}; + +struct FJSONState +{ + /** Key */ + FString Key; + + /** Data */ + FString Data; + + /** Root object */ + TSharedPtr Root; + + /** Object list */ + TArray> Objects; + + /** Tokens */ + TArray Tokens; + + /** Notation */ + EJSONNotation Notation; + + /** Current char has escape */ + bool bEscape; + + /** Has error */ + int32 bError; + + /** Las quote for string */ + TCHAR Quote; + + /** Default constructor */ + FJSONState(); + + EJSONToken GetToken(int32 Index = 0); + + FORCEINLINE bool CheckTokens(EJSONToken T1); + + FORCEINLINE bool CheckTokens(EJSONToken T1, EJSONToken T2); + + FORCEINLINE bool CheckTokens(EJSONToken T1, EJSONToken T2, EJSONToken T3); + + FORCEINLINE void PopToken(int32 Num); + + FORCEINLINE void PopObject(); + + FORCEINLINE void PopArray(); + + FORCEINLINE void PopValue(bool bCheckType = true); + + FORCEINLINE FJsonValue* GetLast(); + + FORCEINLINE FJsonValueObject* GetObject(); + + FORCEINLINE FJsonValueNonConstArray* GetArray(); + + FORCEINLINE TSharedPtr PushObject(); + + FORCEINLINE TSharedPtr PushObject(TSharedPtr Object); + + FORCEINLINE TSharedPtr PushArray(); + + FORCEINLINE TSharedPtr PushBoolean(); + + FORCEINLINE TSharedPtr PushNull(); + + FORCEINLINE TSharedPtr PushNumber(); + + FORCEINLINE TSharedPtr PushString(); + + FORCEINLINE void ClearData(); + + FORCEINLINE void ClearKey(); + + FORCEINLINE void DataToKey(); + + FORCEINLINE void Error(); + +}; + +struct FJSONReader +{ + /** State */ + FJSONState State; + + /** Default constructor */ + FJSONReader(); + +private: + + FORCEINLINE bool IsNewLine(const TCHAR& Char); + + FORCEINLINE bool IsSpace(const TCHAR& Char); + + FORCEINLINE bool FindToken(const TCHAR& Char); + + FORCEINLINE void UpdateNotation(); + + FORCEINLINE void ReadAsString(const TCHAR& Char); + + FORCEINLINE void ReadAsStringSpecial(const TCHAR& Char); + + FORCEINLINE void ReadAsNumber(const TCHAR& Char); + + FORCEINLINE void ReadBasicValue(const TCHAR& Char); + + FORCEINLINE void ReadAsArray(const TCHAR& Char); + + FORCEINLINE void ReadAsObject(const TCHAR& Char); + + FORCEINLINE void Skip(const TCHAR& Char); + +public: + + bool Read(const TCHAR Char); // @Pushkin + +}; + +struct FJSONWriter +{ + FJSONWriter(); + + FORCEINLINE bool GetStartChar(const TSharedPtr& JsonValue, FString& Char); + + FORCEINLINE bool GetEndChar(const TSharedPtr& JsonValue, FString& Char); + +public: + void Write(TSharedPtr JsonValue, FArchive* Writer, bool IsLastElement); // @Pushkin +}; diff --git a/Source/VaRestPlugin/Private/VaRestRequestJSON.cpp b/Source/VaRestPlugin/Private/VaRestRequestJSON.cpp index 3e9d6d36..99803058 100644 --- a/Source/VaRestPlugin/Private/VaRestRequestJSON.cpp +++ b/Source/VaRestPlugin/Private/VaRestRequestJSON.cpp @@ -419,11 +419,10 @@ void UVaRestRequestJSON::OnProcessRequestComplete(FHttpRequestPtr Request, FHttp return; } - // Save response data as a string - ResponseContent = Response->GetContentAsString(); - +#if !(PLATFORM_IOS || PLATFORM_ANDROID) // Log response state - UE_LOG(LogVaRest, Log, TEXT("Response (%d): %sJSON(%s%s%s)JSON"), ResponseCode, LINE_TERMINATOR, LINE_TERMINATOR, *ResponseContent, LINE_TERMINATOR); + UE_LOG(LogVaRest, Log, TEXT("Response (%d): %sJSON(%s%s%s)JSON"), ResponseCode, LINE_TERMINATOR, LINE_TERMINATOR, *Response->GetContentAsString(), LINE_TERMINATOR); +#endif // Process response headers TArray Headers = Response->GetAllHeaders(); @@ -436,14 +435,20 @@ void UVaRestRequestJSON::OnProcessRequestComplete(FHttpRequestPtr Request, FHttp ResponseHeaders.Add(Key, Value); } } - + // Try to deserialize data to JSON - TSharedRef> JsonReader = TJsonReaderFactory::Create(ResponseContent); - FJsonSerializer::Deserialize(JsonReader, ResponseJsonObj->GetRootObject()); - + const TArray& Bytes = Response->GetContent(); + ResponseJsonObj->DeserializeFromUTF8Bytes((const ANSICHAR*) Bytes.GetData(), Bytes.Num()); + // Decide whether the request was successful bIsValidJsonResponse = bWasSuccessful && ResponseJsonObj->GetRootObject().IsValid(); + if (!bIsValidJsonResponse) + { + // Save response data as a string + ResponseContent = Response->GetContentAsString(); + } + // Log errors if (!bIsValidJsonResponse) { From 269077260efa61a0f4b418e738946c8a88754cbb Mon Sep 17 00:00:00 2001 From: "v.alyamkin" Date: Wed, 4 Oct 2017 16:52:31 +0300 Subject: [PATCH 02/24] Minor refactoring --- Source/VaRestPlugin/Classes/VaRestJsonObject.h | 4 +++- Source/VaRestPlugin/Classes/VaRestRequestJSON.h | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/Source/VaRestPlugin/Classes/VaRestJsonObject.h b/Source/VaRestPlugin/Classes/VaRestJsonObject.h index 09f39333..3c2e289c 100644 --- a/Source/VaRestPlugin/Classes/VaRestJsonObject.h +++ b/Source/VaRestPlugin/Classes/VaRestJsonObject.h @@ -166,16 +166,17 @@ class VARESTPLUGIN_API UVaRestJsonObject : public UObject UFUNCTION(BlueprintCallable, Category = "VaRest|Json") void SetObjectArrayField(const FString& FieldName, const TArray& ObjectArray); + ////////////////////////////////////////////////////////////////////////// // Deserialize +public: /** Deserialize byte content to json */ void DeserializeFromUTF8Bytes(const ANSICHAR* Bytes, int32 Size); /** Deserialize byte content to json */ void DeserializeFromTCHARBytes(const TCHAR* Bytes, int32 Size); -public: /** Deserialize byte stream from reader */ void DecodeFromArchive(TUniquePtr& Reader); @@ -184,6 +185,7 @@ class VARESTPLUGIN_API UVaRestJsonObject : public UObject static bool WriteStringToArchive(FArchive& Ar, const TCHAR* StrPtr, int64 Len); + ////////////////////////////////////////////////////////////////////////// // Data diff --git a/Source/VaRestPlugin/Classes/VaRestRequestJSON.h b/Source/VaRestPlugin/Classes/VaRestRequestJSON.h index 78cc11b0..d3b43c8a 100644 --- a/Source/VaRestPlugin/Classes/VaRestRequestJSON.h +++ b/Source/VaRestPlugin/Classes/VaRestRequestJSON.h @@ -210,6 +210,7 @@ class VARESTPLUGIN_API UVaRestRequestJSON : public UObject /** Apply current internal setup to request and process it */ void ProcessRequest(); + ////////////////////////////////////////////////////////////////////////// // Request callbacks From fda68c9baad80f7ba290cd303bea5d68502a9a75 Mon Sep 17 00:00:00 2001 From: "v.alyamkin" Date: Wed, 4 Oct 2017 17:14:27 +0300 Subject: [PATCH 03/24] Comment #122 --- Source/VaRestPlugin/Classes/VaRestRequestJSON.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/VaRestPlugin/Classes/VaRestRequestJSON.h b/Source/VaRestPlugin/Classes/VaRestRequestJSON.h index d3b43c8a..c3befb5f 100644 --- a/Source/VaRestPlugin/Classes/VaRestRequestJSON.h +++ b/Source/VaRestPlugin/Classes/VaRestRequestJSON.h @@ -263,7 +263,7 @@ class VARESTPLUGIN_API UVaRestRequestJSON : public UObject // Data public: - /** Request response stored as a string */ + /** Request response stored as a string (Attn.! For invalid responses only, empty for valid one - use json response object instead */ UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "VaRest|Response") FString ResponseContent; From 1f43af1731a0e6f2afe54e144606a247783bdcdc Mon Sep 17 00:00:00 2001 From: "v.alyamkin" Date: Wed, 11 Oct 2017 14:54:21 +0300 Subject: [PATCH 04/24] Temporary solutions for Pushkin --- Source/VaRestPlugin/Classes/VaRestRequestJSON.h | 5 +++++ .../VaRestPlugin/Private/VaRestRequestJSON.cpp | 16 ++++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/Source/VaRestPlugin/Classes/VaRestRequestJSON.h b/Source/VaRestPlugin/Classes/VaRestRequestJSON.h index c3befb5f..7aca48a7 100644 --- a/Source/VaRestPlugin/Classes/VaRestRequestJSON.h +++ b/Source/VaRestPlugin/Classes/VaRestRequestJSON.h @@ -3,6 +3,7 @@ #pragma once #include "Engine/LatentActionManager.h" +#include "LatentActions.h" #include "Http.h" #include "VaRestTypes.h" @@ -157,6 +158,10 @@ class VARESTPLUGIN_API UVaRestRequestJSON : public UObject UFUNCTION(BlueprintCallable, Category = "VaRest|Response") UVaRestJsonObject* GetResponseObject(); + /** @temp */ + UFUNCTION(BlueprintCallable, Category = "VaRest|Response") + UVaRestJsonObject* GetResponseRootObject(); + /** Set the Response Json object */ UFUNCTION(BlueprintCallable, Category = "VaRest|Response") void SetResponseObject(UVaRestJsonObject* JsonObject); diff --git a/Source/VaRestPlugin/Private/VaRestRequestJSON.cpp b/Source/VaRestPlugin/Private/VaRestRequestJSON.cpp index 99803058..aa72b29e 100644 --- a/Source/VaRestPlugin/Private/VaRestRequestJSON.cpp +++ b/Source/VaRestPlugin/Private/VaRestRequestJSON.cpp @@ -144,6 +144,22 @@ void UVaRestRequestJSON::SetRequestObject(UVaRestJsonObject* JsonObject) } UVaRestJsonObject* UVaRestRequestJSON::GetResponseObject() +{ + // @temp for tests + if (ResponseJsonObj && ResponseJsonObj->IsValidLowLevel()) + { + if (ResponseJsonObj->HasField("body")) + { + return ResponseJsonObj->GetObjectField("body"); + } + + return ResponseJsonObj; + } + + return ResponseJsonObj; +} + +UVaRestJsonObject* UVaRestRequestJSON::GetResponseRootObject() { return ResponseJsonObj; } From e9646782f8acdb9845d46419d2a7e69dd4a05190 Mon Sep 17 00:00:00 2001 From: "v.alyamkin" Date: Wed, 11 Oct 2017 14:54:49 +0300 Subject: [PATCH 05/24] Stay on UE 4.16 for now --- VaRestPlugin.uplugin | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/VaRestPlugin.uplugin b/VaRestPlugin.uplugin index c7c3875d..e55de986 100644 --- a/VaRestPlugin.uplugin +++ b/VaRestPlugin.uplugin @@ -2,11 +2,11 @@ "FileVersion" : 3, "FriendlyName" : "VaRest", - "Version" : 18, - "VersionName" : "1.1-r18", + "Version" : 17, + "VersionName" : "1.1-r17", "CreatedBy" : "Vladimir Alyamkin", "CreatedByURL" : "http://alyamkin.com", - "EngineVersion" : "4.17.0", + "EngineVersion" : "4.16.0", "Description" : "Plugin that makes REST (JSON) server communication easy to use", "Category" : "Network", "MarketplaceURL" : "com.epicgames.launcher://ue/marketplace/content/e47be161e7a24e928560290abd5dcc4f", From 7367a14d60fde4483b9dd3f8646a8ee0c0327da4 Mon Sep 17 00:00:00 2001 From: "v.alyamkin" Date: Wed, 25 Oct 2017 15:52:18 +0300 Subject: [PATCH 06/24] Add UE 4.18 support --- README.md | 2 +- Source/VaRestPlugin/Private/VaRestRequestJSON.cpp | 14 ++++++++++++++ VaRestPlugin.uplugin | 6 +++--- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 9b5f505b..aa274522 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Key features: Check the [Wiki](https://hiazma.atlassian.net/wiki/display/VAR) for plugin usage examples and installation notes. -Current version: **1.1 R 18** (UE 4.16-4.17) +Current version: **1.1 R 19** (UE 4.16-4.18) ![SCREENSHOT](SCREENSHOT.jpg) diff --git a/Source/VaRestPlugin/Private/VaRestRequestJSON.cpp b/Source/VaRestPlugin/Private/VaRestRequestJSON.cpp index 99803058..9a9130eb 100644 --- a/Source/VaRestPlugin/Private/VaRestRequestJSON.cpp +++ b/Source/VaRestPlugin/Private/VaRestRequestJSON.cpp @@ -3,6 +3,8 @@ #include "VaRestPluginPrivatePCH.h" #include "CoreMisc.h" +#include "Runtime/Launch/Resources/Version.h" + template void FVaRestLatentAction::Cancel() { UObject *Obj = Request.Get(); @@ -203,8 +205,14 @@ void UVaRestRequestJSON::SetURL(const FString& Url) { // Be sure to trim URL because it can break links on iOS FString TrimmedUrl = Url; + +#if ENGINE_MINOR_VERSION >= 18 + TrimmedUrl.TrimStartInline(); + TrimmedUrl.TrimEndInline(); +#else TrimmedUrl.Trim(); TrimmedUrl.TrimTrailing(); +#endif HttpRequest->SetURL(TrimmedUrl); } @@ -219,8 +227,14 @@ void UVaRestRequestJSON::ApplyURL(const FString& Url, UVaRestJsonObject *&Result { // Be sure to trim URL because it can break links on iOS FString TrimmedUrl = Url; + +#if ENGINE_MINOR_VERSION >= 18 + TrimmedUrl.TrimStartInline(); + TrimmedUrl.TrimEndInline(); +#else TrimmedUrl.Trim(); TrimmedUrl.TrimTrailing(); +#endif HttpRequest->SetURL(TrimmedUrl); diff --git a/VaRestPlugin.uplugin b/VaRestPlugin.uplugin index c7c3875d..05b95ec6 100644 --- a/VaRestPlugin.uplugin +++ b/VaRestPlugin.uplugin @@ -2,11 +2,11 @@ "FileVersion" : 3, "FriendlyName" : "VaRest", - "Version" : 18, - "VersionName" : "1.1-r18", + "Version" : 19, + "VersionName" : "1.1-r19", "CreatedBy" : "Vladimir Alyamkin", "CreatedByURL" : "http://alyamkin.com", - "EngineVersion" : "4.17.0", + "EngineVersion" : "4.18.0", "Description" : "Plugin that makes REST (JSON) server communication easy to use", "Category" : "Network", "MarketplaceURL" : "com.epicgames.launcher://ue/marketplace/content/e47be161e7a24e928560290abd5dcc4f", From 27151651223e9634ef56e5f57fb82672a2e27abf Mon Sep 17 00:00:00 2001 From: "v.alyamkin" Date: Mon, 30 Oct 2017 13:45:25 +0300 Subject: [PATCH 07/24] Update headers to disable PCH usage --- Source/VaRestPlugin/Classes/VaRestRequestJSON.h | 2 +- Source/VaRestPlugin/Private/VaRestJsonObject.cpp | 4 +++- Source/VaRestPlugin/Private/VaRestJsonParser.cpp | 1 - Source/VaRestPlugin/Private/VaRestJsonValue.cpp | 2 +- Source/VaRestPlugin/Private/VaRestLibrary.cpp | 3 ++- Source/VaRestPlugin/Private/VaRestPlugin.cpp | 2 +- Source/VaRestPlugin/Private/VaRestPluginPrivatePCH.h | 3 --- Source/VaRestPlugin/Private/VaRestRequestJSON.cpp | 2 +- .../VaRestPlugin/Public/{IVaRestPlugin.h => VaRestPlugin.h} | 0 Source/VaRestPlugin/VaRestPlugin.Build.cs | 2 ++ 10 files changed, 11 insertions(+), 10 deletions(-) rename Source/VaRestPlugin/Public/{IVaRestPlugin.h => VaRestPlugin.h} (100%) diff --git a/Source/VaRestPlugin/Classes/VaRestRequestJSON.h b/Source/VaRestPlugin/Classes/VaRestRequestJSON.h index c3befb5f..884e70cd 100644 --- a/Source/VaRestPlugin/Classes/VaRestRequestJSON.h +++ b/Source/VaRestPlugin/Classes/VaRestRequestJSON.h @@ -2,7 +2,7 @@ #pragma once -#include "Engine/LatentActionManager.h" +#include "LatentActions.h" #include "Http.h" #include "VaRestTypes.h" diff --git a/Source/VaRestPlugin/Private/VaRestJsonObject.cpp b/Source/VaRestPlugin/Private/VaRestJsonObject.cpp index 654e6893..3903dfbb 100644 --- a/Source/VaRestPlugin/Private/VaRestJsonObject.cpp +++ b/Source/VaRestPlugin/Private/VaRestJsonObject.cpp @@ -1,7 +1,9 @@ // Copyright 2014 Vladimir Alyamkin. All Rights Reserved. -#include "VaRestPluginPrivatePCH.h" +#include "VaRestJsonObject.h" #include "VaRestJsonParser.h" +#include "VaRestJsonValue.h" +#include "VaRestPluginPrivatePCH.h" typedef TJsonWriterFactory< TCHAR, TCondensedJsonPrintPolicy > FCondensedJsonStringWriterFactory; typedef TJsonWriter< TCHAR, TCondensedJsonPrintPolicy > FCondensedJsonStringWriter; diff --git a/Source/VaRestPlugin/Private/VaRestJsonParser.cpp b/Source/VaRestPlugin/Private/VaRestJsonParser.cpp index 755ada3a..59ae722f 100644 --- a/Source/VaRestPlugin/Private/VaRestJsonParser.cpp +++ b/Source/VaRestPlugin/Private/VaRestJsonParser.cpp @@ -1,6 +1,5 @@ // Copyright 2015-2017 Mail.Ru Group. All Rights Reserved. -#include "VaRestPluginPrivatePCH.h" #include "VaRestJsonParser.h" #include "VaRestJsonObject.h" #include "Dom/JsonObject.h" diff --git a/Source/VaRestPlugin/Private/VaRestJsonValue.cpp b/Source/VaRestPlugin/Private/VaRestJsonValue.cpp index fd767f9f..832fa0a4 100644 --- a/Source/VaRestPlugin/Private/VaRestJsonValue.cpp +++ b/Source/VaRestPlugin/Private/VaRestJsonValue.cpp @@ -1,6 +1,6 @@ // Copyright 2014 Vladimir Alyamkin. All Rights Reserved. -#include "VaRestPluginPrivatePCH.h" +#include "VaRestJsonValue.h" UVaRestJsonValue::UVaRestJsonValue(const class FObjectInitializer& PCIP) : Super(PCIP) diff --git a/Source/VaRestPlugin/Private/VaRestLibrary.cpp b/Source/VaRestPlugin/Private/VaRestLibrary.cpp index 1a532d65..52941571 100644 --- a/Source/VaRestPlugin/Private/VaRestLibrary.cpp +++ b/Source/VaRestPlugin/Private/VaRestLibrary.cpp @@ -1,6 +1,7 @@ // Copyright 2016 Vladimir Alyamkin. All Rights Reserved. -#include "VaRestPluginPrivatePCH.h" +#include "VaRestLibrary.h" +#include "VaRestRequestJSON.h" #include "Base64.h" ////////////////////////////////////////////////////////////////////////// diff --git a/Source/VaRestPlugin/Private/VaRestPlugin.cpp b/Source/VaRestPlugin/Private/VaRestPlugin.cpp index 3f22758f..ab5b20e0 100644 --- a/Source/VaRestPlugin/Private/VaRestPlugin.cpp +++ b/Source/VaRestPlugin/Private/VaRestPlugin.cpp @@ -1,6 +1,6 @@ // Copyright 2014 Vladimir Alyamkin. All Rights Reserved. -#include "VaRestPluginPrivatePCH.h" +#include "VaRestPlugin.h" class FVaRestPlugin : public IVaRestPlugin { diff --git a/Source/VaRestPlugin/Private/VaRestPluginPrivatePCH.h b/Source/VaRestPlugin/Private/VaRestPluginPrivatePCH.h index 85f6f2d6..d88b7f1e 100644 --- a/Source/VaRestPlugin/Private/VaRestPluginPrivatePCH.h +++ b/Source/VaRestPlugin/Private/VaRestPluginPrivatePCH.h @@ -28,6 +28,3 @@ DECLARE_LOG_CATEGORY_EXTERN(LogVaRest, Log, All); -#include "IVaRestPlugin.h" - -#include "VaRestPluginClasses.h" diff --git a/Source/VaRestPlugin/Private/VaRestRequestJSON.cpp b/Source/VaRestPlugin/Private/VaRestRequestJSON.cpp index 9a9130eb..861159ea 100644 --- a/Source/VaRestPlugin/Private/VaRestRequestJSON.cpp +++ b/Source/VaRestPlugin/Private/VaRestRequestJSON.cpp @@ -1,6 +1,6 @@ // Copyright 2014 Vladimir Alyamkin. All Rights Reserved. -#include "VaRestPluginPrivatePCH.h" +#include "VaRestRequestJSON.h" #include "CoreMisc.h" #include "Runtime/Launch/Resources/Version.h" diff --git a/Source/VaRestPlugin/Public/IVaRestPlugin.h b/Source/VaRestPlugin/Public/VaRestPlugin.h similarity index 100% rename from Source/VaRestPlugin/Public/IVaRestPlugin.h rename to Source/VaRestPlugin/Public/VaRestPlugin.h diff --git a/Source/VaRestPlugin/VaRestPlugin.Build.cs b/Source/VaRestPlugin/VaRestPlugin.Build.cs index 83ef5ff9..b16ef0c4 100644 --- a/Source/VaRestPlugin/VaRestPlugin.Build.cs +++ b/Source/VaRestPlugin/VaRestPlugin.Build.cs @@ -8,6 +8,8 @@ public class VaRestPlugin : ModuleRules { public VaRestPlugin(ReadOnlyTargetRules Target) : base(Target) { + PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; + PrivateIncludePaths.AddRange( new string[] { "VaRestPlugin/Private", From 1a46615a224c1ddf5822ca80cf48fb304cd7f89d Mon Sep 17 00:00:00 2001 From: "v.alyamkin" Date: Tue, 31 Oct 2017 15:31:56 +0300 Subject: [PATCH 08/24] Fix IWYU --- .../Private/VaRestEditorPlugin.cpp | 1 - .../Private/VaRestEditorPluginPrivatePCH.h | 16 ---------------- .../Private/VaRest_BreakJson.cpp | 10 ++++++++-- .../VaRestEditorPlugin.Build.cs | 5 +++-- 4 files changed, 11 insertions(+), 21 deletions(-) delete mode 100644 Source/VaRestEditorPlugin/Private/VaRestEditorPluginPrivatePCH.h diff --git a/Source/VaRestEditorPlugin/Private/VaRestEditorPlugin.cpp b/Source/VaRestEditorPlugin/Private/VaRestEditorPlugin.cpp index 04525c2f..f274a924 100644 --- a/Source/VaRestEditorPlugin/Private/VaRestEditorPlugin.cpp +++ b/Source/VaRestEditorPlugin/Private/VaRestEditorPlugin.cpp @@ -1,7 +1,6 @@ // Copyright 2015 Vladimir Alyamkin. All Rights Reserved. // Original code by https://github.com/unktomi -#include "VaRestEditorPluginPrivatePCH.h" #include "VaRestEditorPlugin.h" #define LOCTEXT_NAMESPACE "FVaRestEditorPluginModule" diff --git a/Source/VaRestEditorPlugin/Private/VaRestEditorPluginPrivatePCH.h b/Source/VaRestEditorPlugin/Private/VaRestEditorPluginPrivatePCH.h deleted file mode 100644 index a76f3887..00000000 --- a/Source/VaRestEditorPlugin/Private/VaRestEditorPluginPrivatePCH.h +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2015 Vladimir Alyamkin. All Rights Reserved. -// Original code by https://github.com/unktomi - -#pragma once - -#include "KismetCompiler.h" -#include "EditorCategoryUtils.h" -#include "EdGraph/EdGraph.h" -#include "EdGraph/EdGraphNodeUtils.h" // for FNodeTextCache -#include "EdGraphSchema_K2.h" -#include "BlueprintNodeSpawner.h" -#include "BlueprintActionDatabaseRegistrar.h" -#include "BlueprintFieldNodeSpawner.h" -#include "EditorCategoryUtils.h" -#include "BlueprintActionFilter.h" - diff --git a/Source/VaRestEditorPlugin/Private/VaRest_BreakJson.cpp b/Source/VaRestEditorPlugin/Private/VaRest_BreakJson.cpp index 76d8024f..8997ba7c 100644 --- a/Source/VaRestEditorPlugin/Private/VaRest_BreakJson.cpp +++ b/Source/VaRestEditorPlugin/Private/VaRest_BreakJson.cpp @@ -1,11 +1,17 @@ // Copyright 2015 Vladimir Alyamkin. All Rights Reserved. // Original code by https://github.com/unktomi -#include "VaRestEditorPluginPrivatePCH.h" #include "VaRest_BreakJson.h" -#include "Runtime/Launch/Resources/Version.h" +#include "KismetCompiler.h" +#include "EditorCategoryUtils.h" #include "EdGraphUtilities.h" +#include "EdGraph/EdGraph.h" +#include "EdGraph/EdGraphNodeUtils.h" // for FNodeTextCache +#include "BlueprintNodeSpawner.h" +#include "BlueprintActionDatabaseRegistrar.h" + +#include "Runtime/Launch/Resources/Version.h" #define LOCTEXT_NAMESPACE "VaRest_BreakJson" diff --git a/Source/VaRestEditorPlugin/VaRestEditorPlugin.Build.cs b/Source/VaRestEditorPlugin/VaRestEditorPlugin.Build.cs index f4280a49..86b57861 100644 --- a/Source/VaRestEditorPlugin/VaRestEditorPlugin.Build.cs +++ b/Source/VaRestEditorPlugin/VaRestEditorPlugin.Build.cs @@ -6,8 +6,9 @@ public class VaRestEditorPlugin : ModuleRules { public VaRestEditorPlugin(ReadOnlyTargetRules Target) : base(Target) { - - PublicIncludePaths.AddRange( + PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs; + + PublicIncludePaths.AddRange( new string[] { "VaRestPlugin", "VaRestPlugin/Public" From b799f3accff4c0e6263944ab291c67851d399299 Mon Sep 17 00:00:00 2001 From: "v.alyamkin" Date: Tue, 31 Oct 2017 15:48:47 +0300 Subject: [PATCH 09/24] Fix branch --- Source/VaRestPlugin/Classes/VaRestRequestJSON.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Source/VaRestPlugin/Classes/VaRestRequestJSON.h b/Source/VaRestPlugin/Classes/VaRestRequestJSON.h index 884e70cd..7aca48a7 100644 --- a/Source/VaRestPlugin/Classes/VaRestRequestJSON.h +++ b/Source/VaRestPlugin/Classes/VaRestRequestJSON.h @@ -2,6 +2,7 @@ #pragma once +#include "Engine/LatentActionManager.h" #include "LatentActions.h" #include "Http.h" @@ -157,6 +158,10 @@ class VARESTPLUGIN_API UVaRestRequestJSON : public UObject UFUNCTION(BlueprintCallable, Category = "VaRest|Response") UVaRestJsonObject* GetResponseObject(); + /** @temp */ + UFUNCTION(BlueprintCallable, Category = "VaRest|Response") + UVaRestJsonObject* GetResponseRootObject(); + /** Set the Response Json object */ UFUNCTION(BlueprintCallable, Category = "VaRest|Response") void SetResponseObject(UVaRestJsonObject* JsonObject); From eece4b79ac4fa95d3bb437b26764b869000e44ec Mon Sep 17 00:00:00 2001 From: "v.alyamkin" Date: Tue, 31 Oct 2017 15:49:02 +0300 Subject: [PATCH 10/24] Fix compilation --- Source/VaRestPlugin/Classes/VaRestRequestJSON.h | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/VaRestPlugin/Classes/VaRestRequestJSON.h b/Source/VaRestPlugin/Classes/VaRestRequestJSON.h index 884e70cd..9591028d 100644 --- a/Source/VaRestPlugin/Classes/VaRestRequestJSON.h +++ b/Source/VaRestPlugin/Classes/VaRestRequestJSON.h @@ -2,6 +2,7 @@ #pragma once +#include "Engine/LatentActionManager.h" #include "LatentActions.h" #include "Http.h" From 95cccf759a7201e93638ecb08788a6296baa7fa0 Mon Sep 17 00:00:00 2001 From: "v.alyamkin" Date: Tue, 31 Oct 2017 16:28:53 +0300 Subject: [PATCH 11/24] Fix plugin for non-unity build --- Source/VaRestPlugin/Private/VaRestJsonValue.cpp | 2 ++ Source/VaRestPlugin/Private/VaRestLibrary.cpp | 2 ++ Source/VaRestPlugin/Private/VaRestPlugin.cpp | 4 ++++ Source/VaRestPlugin/Private/VaRestRequestJSON.cpp | 5 ++++- 4 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Source/VaRestPlugin/Private/VaRestJsonValue.cpp b/Source/VaRestPlugin/Private/VaRestJsonValue.cpp index 832fa0a4..a4d5c887 100644 --- a/Source/VaRestPlugin/Private/VaRestJsonValue.cpp +++ b/Source/VaRestPlugin/Private/VaRestJsonValue.cpp @@ -1,6 +1,8 @@ // Copyright 2014 Vladimir Alyamkin. All Rights Reserved. #include "VaRestJsonValue.h" +#include "VaRestJsonObject.h" +#include "VaRestPluginPrivatePCH.h" UVaRestJsonValue::UVaRestJsonValue(const class FObjectInitializer& PCIP) : Super(PCIP) diff --git a/Source/VaRestPlugin/Private/VaRestLibrary.cpp b/Source/VaRestPlugin/Private/VaRestLibrary.cpp index 52941571..9d3c880e 100644 --- a/Source/VaRestPlugin/Private/VaRestLibrary.cpp +++ b/Source/VaRestPlugin/Private/VaRestLibrary.cpp @@ -2,6 +2,8 @@ #include "VaRestLibrary.h" #include "VaRestRequestJSON.h" +#include "VaRestJsonObject.h" +#include "VaRestPluginPrivatePCH.h" #include "Base64.h" ////////////////////////////////////////////////////////////////////////// diff --git a/Source/VaRestPlugin/Private/VaRestPlugin.cpp b/Source/VaRestPlugin/Private/VaRestPlugin.cpp index ab5b20e0..f6386199 100644 --- a/Source/VaRestPlugin/Private/VaRestPlugin.cpp +++ b/Source/VaRestPlugin/Private/VaRestPlugin.cpp @@ -1,6 +1,10 @@ // Copyright 2014 Vladimir Alyamkin. All Rights Reserved. #include "VaRestPlugin.h" +#include "VaRestJsonObject.h" +#include "VaRestJsonValue.h" +#include "VaRestRequestJSON.h" +#include "VaRestPluginPrivatePCH.h" class FVaRestPlugin : public IVaRestPlugin { diff --git a/Source/VaRestPlugin/Private/VaRestRequestJSON.cpp b/Source/VaRestPlugin/Private/VaRestRequestJSON.cpp index 861159ea..77645be3 100644 --- a/Source/VaRestPlugin/Private/VaRestRequestJSON.cpp +++ b/Source/VaRestPlugin/Private/VaRestRequestJSON.cpp @@ -1,8 +1,11 @@ // Copyright 2014 Vladimir Alyamkin. All Rights Reserved. #include "VaRestRequestJSON.h" -#include "CoreMisc.h" +#include "VaRestJsonObject.h" +#include "VaRestLibrary.h" +#include "VaRestPluginPrivatePCH.h" +#include "CoreMisc.h" #include "Runtime/Launch/Resources/Version.h" template void FVaRestLatentAction::Cancel() From cf0c18656ee2c4ea9d17a3b920578732d6a7b5d2 Mon Sep 17 00:00:00 2001 From: "v.alyamkin" Date: Tue, 31 Oct 2017 16:47:14 +0300 Subject: [PATCH 12/24] Fix plugin compilation --- Source/VaRestPlugin/Private/VaRestJsonParser.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Source/VaRestPlugin/Private/VaRestJsonParser.h b/Source/VaRestPlugin/Private/VaRestJsonParser.h index 9a9ef42c..58bb0adc 100644 --- a/Source/VaRestPlugin/Private/VaRestJsonParser.h +++ b/Source/VaRestPlugin/Private/VaRestJsonParser.h @@ -2,6 +2,8 @@ #pragma once +#include "Json.h" + class FJsonValueNonConstArray : public FJsonValueArray { public: From a97a6e4b0d123b93838ea9262c27c67d73991b59 Mon Sep 17 00:00:00 2001 From: "v.alyamkin" Date: Wed, 1 Nov 2017 18:34:28 +0300 Subject: [PATCH 13/24] Add getter for response content (fix Request Response Content string empty #127) --- .../VaRestPlugin/Classes/VaRestRequestJSON.h | 14 ++++++- .../Private/VaRestPluginPrivatePCH.h | 3 ++ .../Private/VaRestRequestJSON.cpp | 38 +++++++++++++++++++ 3 files changed, 54 insertions(+), 1 deletion(-) diff --git a/Source/VaRestPlugin/Classes/VaRestRequestJSON.h b/Source/VaRestPlugin/Classes/VaRestRequestJSON.h index 9591028d..e221417e 100644 --- a/Source/VaRestPlugin/Classes/VaRestRequestJSON.h +++ b/Source/VaRestPlugin/Classes/VaRestRequestJSON.h @@ -264,7 +264,15 @@ class VARESTPLUGIN_API UVaRestRequestJSON : public UObject // Data public: - /** Request response stored as a string (Attn.! For invalid responses only, empty for valid one - use json response object instead */ + /** + * Get request response stored as a string + * @param bCacheResponseContent - Set true if you plan to use it few times to prevent deserialization each time + */ + UFUNCTION(BlueprintCallable, Category = "VaRest|Response") + FString GetResponseContentAsString(bool bCacheResponseContent = true); + +public: + /** DEPRECATED: Please use GetResponseContentAsString() instead */ UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "VaRest|Response") FString ResponseContent; @@ -272,6 +280,10 @@ class VARESTPLUGIN_API UVaRestRequestJSON : public UObject UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "VaRest|Response") bool bIsValidJsonResponse; +protected: + /** Default value for deprecated ResponseContent variable */ + static FString DeprecatedResponseString; + protected: /** Latent action helper */ FVaRestLatentAction* ContinueAction; diff --git a/Source/VaRestPlugin/Private/VaRestPluginPrivatePCH.h b/Source/VaRestPlugin/Private/VaRestPluginPrivatePCH.h index d88b7f1e..7e97aaac 100644 --- a/Source/VaRestPlugin/Private/VaRestPluginPrivatePCH.h +++ b/Source/VaRestPlugin/Private/VaRestPluginPrivatePCH.h @@ -28,3 +28,6 @@ DECLARE_LOG_CATEGORY_EXTERN(LogVaRest, Log, All); +#define VA_FUNC (FString(__FUNCTION__)) // Current Class Name + Function Name where this is called +#define VA_LINE (FString::FromInt(__LINE__)) // Current Line Number in the code where this is called +#define VA_FUNC_LINE (VA_FUNC + "(" + VA_LINE + ")") // Current Class and Line Number where this is called! diff --git a/Source/VaRestPlugin/Private/VaRestRequestJSON.cpp b/Source/VaRestPlugin/Private/VaRestRequestJSON.cpp index 77645be3..cd393aa1 100644 --- a/Source/VaRestPlugin/Private/VaRestRequestJSON.cpp +++ b/Source/VaRestPlugin/Private/VaRestRequestJSON.cpp @@ -8,6 +8,8 @@ #include "CoreMisc.h" #include "Runtime/Launch/Resources/Version.h" +FString UVaRestRequestJSON::DeprecatedResponseString(TEXT("DEPRECATED: Please use GetResponseContentAsString() instead")); + template void FVaRestLatentAction::Cancel() { UObject *Obj = Request.Get(); @@ -125,6 +127,9 @@ void UVaRestRequestJSON::ResetResponseData() ResponseCode = -1; bIsValidJsonResponse = false; + + // #127 Reset string to deprecated state + ResponseContent = DeprecatedResponseString; } void UVaRestRequestJSON::Cancel() @@ -512,3 +517,36 @@ bool UVaRestRequestJSON::HasTag(FName Tag) const { return (Tag != NAME_None) && Tags.Contains(Tag); } + + +////////////////////////////////////////////////////////////////////////// +// Data + +FString UVaRestRequestJSON::GetResponseContentAsString(bool bCacheResponseContent) +{ + // Check we have valide response + if (!bIsValidJsonResponse || !ResponseJsonObj || !ResponseJsonObj->IsValidLowLevel()) + { + // Discard previous cached string if we had one + ResponseContent = DeprecatedResponseString; + + return TEXT("Invalid response"); + } + + // Check if we should re-genetate it in runtime + if (!bCacheResponseContent) + { + UE_LOG(LogVaRest, Warning, TEXT("%s: Use of uncashed getter could be slow"), *VA_FUNC_LINE); + return ResponseJsonObj->EncodeJson(); + } + + // Check that we haven't cached content yet + if (ResponseContent == DeprecatedResponseString) + { + UE_LOG(LogVaRest, Warning, TEXT("%s: Response content string is cached"), *VA_FUNC_LINE); + ResponseContent = ResponseJsonObj->EncodeJson(); + } + + // Return previously cached content now + return ResponseContent; +} From c4e4563191e0286c2bea5fa46ae6a258fbecc0ee Mon Sep 17 00:00:00 2001 From: "v.alyamkin" Date: Wed, 1 Nov 2017 18:36:27 +0300 Subject: [PATCH 14/24] Fix GetWorldFromContextObject deprecated #124 --- Source/VaRestPlugin/Private/VaRestLibrary.cpp | 2 +- Source/VaRestPlugin/Private/VaRestRequestJSON.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Source/VaRestPlugin/Private/VaRestLibrary.cpp b/Source/VaRestPlugin/Private/VaRestLibrary.cpp index 9d3c880e..71060a44 100644 --- a/Source/VaRestPlugin/Private/VaRestLibrary.cpp +++ b/Source/VaRestPlugin/Private/VaRestLibrary.cpp @@ -73,7 +73,7 @@ TMap UVaRestLibrary::RequestMap; void UVaRestLibrary::CallURL(UObject* WorldContextObject, const FString& URL, ERequestVerb Verb, ERequestContentType ContentType, UVaRestJsonObject* VaRestJson, const FVaRestCallDelegate& Callback) { - UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject); + UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull); if (World == nullptr) { UE_LOG(LogVaRest, Error, TEXT("UVaRestLibrary: Wrong world context")) diff --git a/Source/VaRestPlugin/Private/VaRestRequestJSON.cpp b/Source/VaRestPlugin/Private/VaRestRequestJSON.cpp index cd393aa1..18942f68 100644 --- a/Source/VaRestPlugin/Private/VaRestRequestJSON.cpp +++ b/Source/VaRestPlugin/Private/VaRestRequestJSON.cpp @@ -247,7 +247,7 @@ void UVaRestRequestJSON::ApplyURL(const FString& Url, UVaRestJsonObject *&Result HttpRequest->SetURL(TrimmedUrl); // Prepare latent action - if (UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject)) + if (UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject, EGetWorldErrorMode::LogAndReturnNull)) { FLatentActionManager& LatentActionManager = World->GetLatentActionManager(); FVaRestLatentAction *Kont = LatentActionManager.FindExistingAction>(LatentInfo.CallbackTarget, LatentInfo.UUID); From 5a9b8cb5fb76ca01b5a466ea231ce9c2f11094a5 Mon Sep 17 00:00:00 2001 From: prudnikov Date: Mon, 18 Dec 2017 12:53:49 +0300 Subject: [PATCH 15/24] Calculate response size --- .../VaRestPlugin/Classes/VaRestJsonObject.h | 4 ++-- .../VaRestPlugin/Classes/VaRestRequestJSON.h | 6 +++++- .../VaRestPlugin/Private/VaRestJsonObject.cpp | 6 ++++-- .../VaRestPlugin/Private/VaRestJsonParser.cpp | 20 +++++++++++++++++-- .../VaRestPlugin/Private/VaRestJsonParser.h | 3 +++ Source/VaRestPlugin/Private/VaRestLibrary.cpp | 2 +- .../Private/VaRestRequestJSON.cpp | 8 +++++--- 7 files changed, 38 insertions(+), 11 deletions(-) diff --git a/Source/VaRestPlugin/Classes/VaRestJsonObject.h b/Source/VaRestPlugin/Classes/VaRestJsonObject.h index 3c2e289c..3d367d6c 100644 --- a/Source/VaRestPlugin/Classes/VaRestJsonObject.h +++ b/Source/VaRestPlugin/Classes/VaRestJsonObject.h @@ -172,10 +172,10 @@ class VARESTPLUGIN_API UVaRestJsonObject : public UObject public: /** Deserialize byte content to json */ - void DeserializeFromUTF8Bytes(const ANSICHAR* Bytes, int32 Size); + int32 DeserializeFromUTF8Bytes(const ANSICHAR* Bytes, int32 Size); /** Deserialize byte content to json */ - void DeserializeFromTCHARBytes(const TCHAR* Bytes, int32 Size); + int32 DeserializeFromTCHARBytes(const TCHAR* Bytes, int32 Size); /** Deserialize byte stream from reader */ void DecodeFromArchive(TUniquePtr& Reader); diff --git a/Source/VaRestPlugin/Classes/VaRestRequestJSON.h b/Source/VaRestPlugin/Classes/VaRestRequestJSON.h index 7aca48a7..f2684967 100644 --- a/Source/VaRestPlugin/Classes/VaRestRequestJSON.h +++ b/Source/VaRestPlugin/Classes/VaRestRequestJSON.h @@ -268,6 +268,10 @@ class VARESTPLUGIN_API UVaRestRequestJSON : public UObject // Data public: + /** Response size */ + UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "VaRest|Response") + int32 ResponseSize; + /** Request response stored as a string (Attn.! For invalid responses only, empty for valid one - use json response object instead */ UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "VaRest|Response") FString ResponseContent; @@ -275,7 +279,7 @@ class VARESTPLUGIN_API UVaRestRequestJSON : public UObject /** Is the response valid JSON? */ UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "VaRest|Response") bool bIsValidJsonResponse; - + protected: /** Latent action helper */ FVaRestLatentAction* ContinueAction; diff --git a/Source/VaRestPlugin/Private/VaRestJsonObject.cpp b/Source/VaRestPlugin/Private/VaRestJsonObject.cpp index 3903dfbb..4aa10f2c 100644 --- a/Source/VaRestPlugin/Private/VaRestJsonObject.cpp +++ b/Source/VaRestPlugin/Private/VaRestJsonObject.cpp @@ -547,7 +547,7 @@ void UVaRestJsonObject::SetObjectArrayField(const FString& FieldName, const TArr ////////////////////////////////////////////////////////////////////////// // Deserialize -void UVaRestJsonObject::DeserializeFromUTF8Bytes(const ANSICHAR* Bytes, int32 Size) +int32 UVaRestJsonObject::DeserializeFromUTF8Bytes(const ANSICHAR* Bytes, int32 Size) { FJSONReader Reader; @@ -568,9 +568,10 @@ void UVaRestJsonObject::DeserializeFromUTF8Bytes(const ANSICHAR* Bytes, int32 Si } SetRootObject(Reader.State.Root); + return Reader.State.Size; } -void UVaRestJsonObject::DeserializeFromTCHARBytes(const TCHAR* Bytes, int32 Size) +int32 UVaRestJsonObject::DeserializeFromTCHARBytes(const TCHAR* Bytes, int32 Size) { FJSONReader Reader; @@ -584,6 +585,7 @@ void UVaRestJsonObject::DeserializeFromTCHARBytes(const TCHAR* Bytes, int32 Size } SetRootObject(Reader.State.Root); + return Reader.State.Size; } void UVaRestJsonObject::DecodeFromArchive(TUniquePtr& Reader) diff --git a/Source/VaRestPlugin/Private/VaRestJsonParser.cpp b/Source/VaRestPlugin/Private/VaRestJsonParser.cpp index 59ae722f..588f3020 100644 --- a/Source/VaRestPlugin/Private/VaRestJsonParser.cpp +++ b/Source/VaRestPlugin/Private/VaRestJsonParser.cpp @@ -21,6 +21,8 @@ FJSONState::FJSONState() Tokens.Reserve(64); Tokens.Add(EJSONToken::ROOT); + + Size = 0; } EJSONToken FJSONState::GetToken(int32 Index) @@ -118,7 +120,10 @@ void FJSONState::PopValue(bool bCheckType) } case EJson::String: { - ((FJsonValueNonConstString*) Value.Get())->AsNonConstString() = Data; + FJsonValueNonConstString* JsonValueString = ((FJsonValueNonConstString*) Value.Get()); + JsonValueString->AsNonConstString() = Data; + JsonValueString->AsNonConstString().Shrink(); + Size += JsonValueString->AsNonConstString().GetAllocatedSize(); break; } case EJson::Number: @@ -165,7 +170,10 @@ void FJSONState::PopValue(bool bCheckType) { if (Key.Len() > 0) { - Container->AsObject()->SetField(Key, Value); + FString KeyCopy = Key; + KeyCopy.Shrink(); + Container->AsObject()->SetField(KeyCopy, Value); + Size += KeyCopy.GetAllocatedSize(); ClearKey(); } else @@ -230,6 +238,7 @@ TSharedPtr FJSONState::PushObject() { TSharedPtr Result(new FJsonValueObject(TSharedPtr(new FJsonObject()))); Objects.Add(Result); + Size += sizeof(TSharedPtr) + sizeof(FJsonValueObject); return Result; } @@ -237,6 +246,7 @@ TSharedPtr FJSONState::PushObject(TSharedPtr Obje { TSharedPtr Result(new FJsonValueObject(Object)); Objects.Add(Result); + Size += sizeof(TSharedPtr) + sizeof(FJsonValueObject); return Result; } @@ -245,6 +255,7 @@ TSharedPtr FJSONState::PushArray() TArray> Empty; TSharedPtr Result(new FJsonValueNonConstArray(Empty)); Objects.Add(Result); + Size += sizeof(TSharedPtr) + sizeof(FJsonValueNonConstArray); return Result; } @@ -252,6 +263,7 @@ TSharedPtr FJSONState::PushBoolean() { TSharedPtr Result(new FJsonValueNonConstBoolean(false)); Objects.Add(Result); + Size += sizeof(TSharedPtr) + sizeof(FJsonValueNonConstBoolean); return Result; } @@ -259,6 +271,7 @@ TSharedPtr FJSONState::PushNull() { TSharedPtr Result(new FJsonValueNull()); Objects.Add(Result); + Size += sizeof(TSharedPtr) + sizeof(FJsonValueNull); return Result; } @@ -266,6 +279,7 @@ TSharedPtr FJSONState::PushNumber() { TSharedPtr Result(new FJsonValueNonConstNumber(0.f)); Objects.Add(Result); + Size += sizeof(TSharedPtr) + sizeof(FJsonValueNonConstNumber); return Result; } @@ -273,6 +287,7 @@ TSharedPtr FJSONState::PushString() { TSharedPtr Result(new FJsonValueNonConstString(TEXT(""))); Objects.Add(Result); + Size += sizeof(TSharedPtr) + sizeof(FJsonValueNonConstString); return Result; } @@ -726,6 +741,7 @@ bool FJSONReader::Read(const TCHAR Char) if (State.bError) { State.Root = TSharedPtr(nullptr); + State.Size = 0; return false; } diff --git a/Source/VaRestPlugin/Private/VaRestJsonParser.h b/Source/VaRestPlugin/Private/VaRestJsonParser.h index 58bb0adc..2595158d 100644 --- a/Source/VaRestPlugin/Private/VaRestJsonParser.h +++ b/Source/VaRestPlugin/Private/VaRestJsonParser.h @@ -92,6 +92,9 @@ struct FJSONState /** Las quote for string */ TCHAR Quote; + /** Size */ + int32 Size; + /** Default constructor */ FJSONState(); diff --git a/Source/VaRestPlugin/Private/VaRestLibrary.cpp b/Source/VaRestPlugin/Private/VaRestLibrary.cpp index 9d3c880e..8da8ec78 100644 --- a/Source/VaRestPlugin/Private/VaRestLibrary.cpp +++ b/Source/VaRestPlugin/Private/VaRestLibrary.cpp @@ -73,7 +73,7 @@ TMap UVaRestLibrary::RequestMap; void UVaRestLibrary::CallURL(UObject* WorldContextObject, const FString& URL, ERequestVerb Verb, ERequestContentType ContentType, UVaRestJsonObject* VaRestJson, const FVaRestCallDelegate& Callback) { - UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject); + UWorld* World = GEngine->GetWorldFromContextObjectChecked(WorldContextObject); if (World == nullptr) { UE_LOG(LogVaRest, Error, TEXT("UVaRestLibrary: Wrong world context")) diff --git a/Source/VaRestPlugin/Private/VaRestRequestJSON.cpp b/Source/VaRestPlugin/Private/VaRestRequestJSON.cpp index ea0543e8..7228a68c 100644 --- a/Source/VaRestPlugin/Private/VaRestRequestJSON.cpp +++ b/Source/VaRestPlugin/Private/VaRestRequestJSON.cpp @@ -123,6 +123,7 @@ void UVaRestRequestJSON::ResetResponseData() ResponseHeaders.Empty(); ResponseCode = -1; + ResponseSize = 0; bIsValidJsonResponse = false; } @@ -258,7 +259,7 @@ void UVaRestRequestJSON::ApplyURL(const FString& Url, UVaRestJsonObject *&Result HttpRequest->SetURL(TrimmedUrl); // Prepare latent action - if (UWorld* World = GEngine->GetWorldFromContextObject(WorldContextObject)) + if (UWorld* World = GEngine->GetWorldFromContextObjectChecked(WorldContextObject)) { FLatentActionManager& LatentActionManager = World->GetLatentActionManager(); FVaRestLatentAction *Kont = LatentActionManager.FindExistingAction>(LatentInfo.CallbackTarget, LatentInfo.UUID); @@ -471,15 +472,16 @@ void UVaRestRequestJSON::OnProcessRequestComplete(FHttpRequestPtr Request, FHttp // Try to deserialize data to JSON const TArray& Bytes = Response->GetContent(); - ResponseJsonObj->DeserializeFromUTF8Bytes((const ANSICHAR*) Bytes.GetData(), Bytes.Num()); + ResponseSize = ResponseJsonObj->DeserializeFromUTF8Bytes((const ANSICHAR*) Bytes.GetData(), Bytes.Num()); // Decide whether the request was successful bIsValidJsonResponse = bWasSuccessful && ResponseJsonObj->GetRootObject().IsValid(); - + if (!bIsValidJsonResponse) { // Save response data as a string ResponseContent = Response->GetContentAsString(); + ResponseSize = ResponseContent.GetAllocatedSize(); } // Log errors From 9d11cf52bf8b6420ac2765c9cc1506c626d85f22 Mon Sep 17 00:00:00 2001 From: prudnikov Date: Mon, 18 Dec 2017 12:54:13 +0300 Subject: [PATCH 16/24] Update to 4.18 --- VaRestPlugin.uplugin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/VaRestPlugin.uplugin b/VaRestPlugin.uplugin index e55de986..76f71b4d 100644 --- a/VaRestPlugin.uplugin +++ b/VaRestPlugin.uplugin @@ -1,12 +1,12 @@ { "FileVersion" : 3, - + "FriendlyName" : "VaRest", "Version" : 17, "VersionName" : "1.1-r17", "CreatedBy" : "Vladimir Alyamkin", "CreatedByURL" : "http://alyamkin.com", - "EngineVersion" : "4.16.0", + "EngineVersion" : "4.18.0", "Description" : "Plugin that makes REST (JSON) server communication easy to use", "Category" : "Network", "MarketplaceURL" : "com.epicgames.launcher://ue/marketplace/content/e47be161e7a24e928560290abd5dcc4f", From 7e15d8008611bab1fc14f8d6198b947a6dd90829 Mon Sep 17 00:00:00 2001 From: prudnikov Date: Wed, 27 Dec 2017 13:22:19 +0300 Subject: [PATCH 17/24] JSON deserialize number https://www.json.org/number.gif --- .../VaRestPlugin/Private/VaRestJsonParser.cpp | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/Source/VaRestPlugin/Private/VaRestJsonParser.cpp b/Source/VaRestPlugin/Private/VaRestJsonParser.cpp index 588f3020..ea669cae 100644 --- a/Source/VaRestPlugin/Private/VaRestJsonParser.cpp +++ b/Source/VaRestPlugin/Private/VaRestJsonParser.cpp @@ -128,10 +128,32 @@ void FJSONState::PopValue(bool bCheckType) } case EJson::Number: { - auto LowerCase = Data.ToLower(); - if (LowerCase.IsNumeric()) + FString LowerCase = Data.ToLower(); + int32 ePosition = INDEX_NONE; + LowerCase.FindChar('e', ePosition); + if (ePosition == INDEX_NONE) + { + if (LowerCase.IsNumeric()) + { + ((FJsonValueNonConstNumber*) Value.Get())->AsNonConstNumber() = FCString::Atod(*LowerCase); + } + else + { + bError = true; + } + } + else if (LowerCase.Len() > ePosition + 2) { - ((FJsonValueNonConstNumber*) Value.Get())->AsNonConstNumber() = FCString::Atod(*LowerCase); + FString Left = LowerCase.Left(ePosition); + FString Rigth = LowerCase.Right(LowerCase.Len() - ePosition - 1); + if (Left.IsNumeric() && Rigth.IsNumeric()) + { + ((FJsonValueNonConstNumber*) Value.Get())->AsNonConstNumber() = FCString::Atod(*Left) * FMath::Pow(10.f, FCString::Atoi(*Rigth)); + } + else + { + bError = true; + } } else { From 2a2c0aea6fcc867e109527edcc797f49f6753123 Mon Sep 17 00:00:00 2001 From: "v.alyamkin" Date: Fri, 12 Jan 2018 20:58:59 +0300 Subject: [PATCH 18/24] Hotfix: Additional json object validation --- .../VaRestPlugin/Private/VaRestJsonObject.cpp | 60 +++++++++---------- 1 file changed, 29 insertions(+), 31 deletions(-) diff --git a/Source/VaRestPlugin/Private/VaRestJsonObject.cpp b/Source/VaRestPlugin/Private/VaRestJsonObject.cpp index 4aa10f2c..7d06c1be 100644 --- a/Source/VaRestPlugin/Private/VaRestJsonObject.cpp +++ b/Source/VaRestPlugin/Private/VaRestJsonObject.cpp @@ -36,7 +36,15 @@ TSharedPtr& UVaRestJsonObject::GetRootObject() void UVaRestJsonObject::SetRootObject(TSharedPtr& JsonObject) { - JsonObj = JsonObject; + if (JsonObject.IsValid()) + { + JsonObj = JsonObject; + } + else + { + UE_LOG(LogVaRest, Error, TEXT("%s: Trying to set invalid json object as root one. Reset now."), *VA_FUNC_LINE); + Reset(); + } } @@ -244,14 +252,15 @@ void UVaRestJsonObject::SetBoolField(const FString& FieldName, bool InValue) TArray UVaRestJsonObject::GetArrayField(const FString& FieldName) const { - if (!JsonObj->HasTypedField(FieldName)) + TArray OutArray; + if (!JsonObj.IsValid() || FieldName.IsEmpty()) { - UE_LOG(LogVaRest, Warning, TEXT("No field with name %s of type Array"), *FieldName); + return OutArray; } - TArray OutArray; - if (!JsonObj.IsValid() || FieldName.IsEmpty()) + if (!JsonObj->HasTypedField(FieldName)) { + UE_LOG(LogVaRest, Warning, TEXT("%s: No field with name %s of type Array"), *VA_FUNC_LINE, *FieldName); return OutArray; } @@ -320,6 +329,11 @@ void UVaRestJsonObject::SetArrayField(const FString& FieldName, const TArrayIsValidLowLevel()) + { + return; + } + TArray Keys = InJsonObject->GetFieldNames(); for (auto Key : Keys) @@ -337,7 +351,7 @@ UVaRestJsonObject* UVaRestJsonObject::GetObjectField(const FString& FieldName) c { if (!JsonObj.IsValid() || !JsonObj->HasTypedField(FieldName)) { - UE_LOG(LogVaRest, Warning, TEXT("No field with name %s of type Object"), *FieldName); + UE_LOG(LogVaRest, Warning, TEXT("%s: No field with name %s of type Object"), *VA_FUNC_LINE, *FieldName); return nullptr; } @@ -351,7 +365,7 @@ UVaRestJsonObject* UVaRestJsonObject::GetObjectField(const FString& FieldName) c void UVaRestJsonObject::SetObjectField(const FString& FieldName, UVaRestJsonObject* JsonObject) { - if (!JsonObj.IsValid() || FieldName.IsEmpty()) + if (!JsonObj.IsValid() || FieldName.IsEmpty() || !JsonObject || !JsonObject->IsValidLowLevel()) { return; } @@ -365,14 +379,10 @@ void UVaRestJsonObject::SetObjectField(const FString& FieldName, UVaRestJsonObje TArray UVaRestJsonObject::GetNumberArrayField(const FString& FieldName) const { - if (!JsonObj->HasTypedField(FieldName)) - { - UE_LOG(LogVaRest, Warning, TEXT("No field with name %s of type Array"), *FieldName); - } - TArray NumberArray; - if (!JsonObj.IsValid() || FieldName.IsEmpty()) + if (!JsonObj.IsValid() || !JsonObj->HasTypedField(FieldName) || FieldName.IsEmpty()) { + UE_LOG(LogVaRest, Warning, TEXT("%s: No field with name %s of type Array"), *VA_FUNC_LINE, *FieldName); return NumberArray; } @@ -410,14 +420,10 @@ void UVaRestJsonObject::SetNumberArrayField(const FString& FieldName, const TArr TArray UVaRestJsonObject::GetStringArrayField(const FString& FieldName) const { - if (!JsonObj->HasTypedField(FieldName)) - { - UE_LOG(LogVaRest, Warning, TEXT("No field with name %s of type Array"), *FieldName); - } - TArray StringArray; - if (!JsonObj.IsValid() || FieldName.IsEmpty()) + if (!JsonObj.IsValid() || !JsonObj->HasTypedField(FieldName) || FieldName.IsEmpty()) { + UE_LOG(LogVaRest, Warning, TEXT("%s: No field with name %s of type Array"), *VA_FUNC_LINE, *FieldName); return StringArray; } @@ -454,14 +460,10 @@ void UVaRestJsonObject::SetStringArrayField(const FString& FieldName, const TArr TArray UVaRestJsonObject::GetBoolArrayField(const FString& FieldName) const { - if (!JsonObj->HasTypedField(FieldName)) - { - UE_LOG(LogVaRest, Warning, TEXT("No field with name %s of type Array"), *FieldName); - } - TArray BoolArray; - if (!JsonObj.IsValid() || FieldName.IsEmpty()) + if (!JsonObj.IsValid() || !JsonObj->HasTypedField(FieldName) || FieldName.IsEmpty()) { + UE_LOG(LogVaRest, Warning, TEXT("%s: No field with name %s of type Array"), *VA_FUNC_LINE, *FieldName); return BoolArray; } @@ -498,14 +500,10 @@ void UVaRestJsonObject::SetBoolArrayField(const FString& FieldName, const TArray TArray UVaRestJsonObject::GetObjectArrayField(const FString& FieldName) const { - if (!JsonObj->HasTypedField(FieldName)) - { - UE_LOG(LogVaRest, Warning, TEXT("No field with name %s of type Array"), *FieldName); - } - TArray OutArray; - if (!JsonObj.IsValid() || FieldName.IsEmpty()) + if (!JsonObj.IsValid() || !JsonObj->HasTypedField(FieldName) || FieldName.IsEmpty()) { + UE_LOG(LogVaRest, Warning, TEXT("%s: No field with name %s of type Array"), *VA_FUNC_LINE, *FieldName); return OutArray; } From 7092b3785aca8ab66c7fd644d36eb680c4552fed Mon Sep 17 00:00:00 2001 From: "v.alyamkin" Date: Fri, 12 Jan 2018 21:08:08 +0300 Subject: [PATCH 19/24] Up release version to 1.1-r20 --- VaRestPlugin.uplugin | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/VaRestPlugin.uplugin b/VaRestPlugin.uplugin index 05b95ec6..c135da31 100644 --- a/VaRestPlugin.uplugin +++ b/VaRestPlugin.uplugin @@ -2,8 +2,8 @@ "FileVersion" : 3, "FriendlyName" : "VaRest", - "Version" : 19, - "VersionName" : "1.1-r19", + "Version" : 20, + "VersionName" : "1.1-r20", "CreatedBy" : "Vladimir Alyamkin", "CreatedByURL" : "http://alyamkin.com", "EngineVersion" : "4.18.0", From dbb7e3594a0c371c7aeaba3807d840ceb8fd1d99 Mon Sep 17 00:00:00 2001 From: Ondrej Hrusovsky Date: Thu, 18 Jan 2018 13:58:49 +0100 Subject: [PATCH 20/24] Added getter for http request --- Source/VaRestPlugin/Classes/VaRestRequestJSON.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Source/VaRestPlugin/Classes/VaRestRequestJSON.h b/Source/VaRestPlugin/Classes/VaRestRequestJSON.h index 834ca1d3..93b079e5 100644 --- a/Source/VaRestPlugin/Classes/VaRestRequestJSON.h +++ b/Source/VaRestPlugin/Classes/VaRestRequestJSON.h @@ -327,5 +327,8 @@ class VARESTPLUGIN_API UVaRestRequestJSON : public UObject /** Request we're currently processing */ TSharedRef HttpRequest = FHttpModule::Get().CreateRequest(); - + +public: + /** Returns reference to internal request object. */ + TSharedRef GetHttpRequest() const { return HttpRequest; }; }; From b31bbc55dd540eb4e566cae348275fb39f04bc39 Mon Sep 17 00:00:00 2001 From: Vladimir Alyamkin Date: Thu, 18 Jan 2018 16:24:47 +0300 Subject: [PATCH 21/24] Update VaRestRequestJSON.h --- Source/VaRestPlugin/Classes/VaRestRequestJSON.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Source/VaRestPlugin/Classes/VaRestRequestJSON.h b/Source/VaRestPlugin/Classes/VaRestRequestJSON.h index 93b079e5..63527e45 100644 --- a/Source/VaRestPlugin/Classes/VaRestRequestJSON.h +++ b/Source/VaRestPlugin/Classes/VaRestRequestJSON.h @@ -329,6 +329,7 @@ class VARESTPLUGIN_API UVaRestRequestJSON : public UObject TSharedRef HttpRequest = FHttpModule::Get().CreateRequest(); public: - /** Returns reference to internal request object. */ + /** Returns reference to internal request object */ TSharedRef GetHttpRequest() const { return HttpRequest; }; + }; From 8f8e61bf1558cd56bd07ba71636caced684a7755 Mon Sep 17 00:00:00 2001 From: "v.alyamkin" Date: Fri, 26 Jan 2018 12:56:49 +0300 Subject: [PATCH 22/24] Read json from local file helper function --- Source/VaRestPlugin/Classes/VaRestLibrary.h | 9 ++++++ Source/VaRestPlugin/Private/VaRestLibrary.cpp | 28 +++++++++++++++++++ 2 files changed, 37 insertions(+) diff --git a/Source/VaRestPlugin/Classes/VaRestLibrary.h b/Source/VaRestPlugin/Classes/VaRestLibrary.h index 304900bd..b0103140 100644 --- a/Source/VaRestPlugin/Classes/VaRestLibrary.h +++ b/Source/VaRestPlugin/Classes/VaRestLibrary.h @@ -93,6 +93,15 @@ class UVaRestLibrary : public UBlueprintFunctionLibrary static bool Base64DecodeData(const FString& Source, TArray& Dest); + ////////////////////////////////////////////////////////////////////////// + // File system integration + +public: + /** Load JSON from formatted text file */ + UFUNCTION(BlueprintCallable, Category = "VaRest|Utility", meta = (WorldContext = "WorldContextObject")) + static class UVaRestJsonObject* LoadJsonFromFile(UObject* WorldContextObject, const FString& Path); + + ////////////////////////////////////////////////////////////////////////// // Easy URL processing diff --git a/Source/VaRestPlugin/Private/VaRestLibrary.cpp b/Source/VaRestPlugin/Private/VaRestLibrary.cpp index 8da8ec78..89be8925 100644 --- a/Source/VaRestPlugin/Private/VaRestLibrary.cpp +++ b/Source/VaRestPlugin/Private/VaRestLibrary.cpp @@ -66,6 +66,34 @@ bool UVaRestLibrary::Base64DecodeData(const FString& Source, TArray& Dest } +////////////////////////////////////////////////////////////////////////// +// File system integration + +class UVaRestJsonObject* UVaRestLibrary::LoadJsonFromFile(UObject* WorldContextObject, const FString& Path) +{ + UVaRestJsonObject* Json = UVaRestJsonObject::ConstructJsonObject(WorldContextObject); + + FString JSONString; + if (FFileHelper::LoadFileToString(JSONString, *(FPaths::ProjectContentDir() + Path))) + { + if (Json->DecodeJson(JSONString)) + { + return Json; + } + else + { + UE_LOG(LogVaRest, Error, TEXT("%s: Can't decode json from file %s"), *VA_FUNC_LINE, *Path); + } + } + else + { + UE_LOG(LogVaRest, Error, TEXT("%s: Can't open file %s"), *VA_FUNC_LINE, *Path); + } + + return nullptr; +} + + ////////////////////////////////////////////////////////////////////////// // Easy URL processing From 8bb0a3ea6be93702d8ebafb4bc06f1d5590281cb Mon Sep 17 00:00:00 2001 From: "v.alyamkin" Date: Fri, 26 Jan 2018 13:01:39 +0300 Subject: [PATCH 23/24] Minor meta fix --- Source/VaRestPlugin/Classes/VaRestLibrary.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Source/VaRestPlugin/Classes/VaRestLibrary.h b/Source/VaRestPlugin/Classes/VaRestLibrary.h index b0103140..86722fd9 100644 --- a/Source/VaRestPlugin/Classes/VaRestLibrary.h +++ b/Source/VaRestPlugin/Classes/VaRestLibrary.h @@ -97,7 +97,10 @@ class UVaRestLibrary : public UBlueprintFunctionLibrary // File system integration public: - /** Load JSON from formatted text file */ + /** + * Load JSON from formatted text file + * @param Path File name relative to the Content folder + */ UFUNCTION(BlueprintCallable, Category = "VaRest|Utility", meta = (WorldContext = "WorldContextObject")) static class UVaRestJsonObject* LoadJsonFromFile(UObject* WorldContextObject, const FString& Path); From 5a75e8bf46bf4a9cf497f3725174b4bd0134a78b Mon Sep 17 00:00:00 2001 From: "v.alyamkin" Date: Wed, 7 Mar 2018 16:52:41 +0300 Subject: [PATCH 24/24] Update version info for 1.1-r20 --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index aa274522..f9bb5190 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Key features: Check the [Wiki](https://hiazma.atlassian.net/wiki/display/VAR) for plugin usage examples and installation notes. -Current version: **1.1 R 19** (UE 4.16-4.18) +Current version: **1.1 R 20** (UE 4.18) ![SCREENSHOT](SCREENSHOT.jpg) @@ -23,5 +23,5 @@ Legal info Unreal® is a trademark or registered trademark of Epic Games, Inc. in the United States of America and elsewhere. -Unreal® Engine, Copyright 1998 – 2017, Epic Games, Inc. All rights reserved. +Unreal® Engine, Copyright 1998 – 2018, Epic Games, Inc. All rights reserved.