diff --git a/Plugins/EasyXMLParser/Binaries/Win64/UnrealEditor-EasyXMLParser.dll b/Plugins/EasyXMLParser/Binaries/Win64/UnrealEditor-EasyXMLParser.dll new file mode 100644 index 00000000..d7a46cc6 Binary files /dev/null and b/Plugins/EasyXMLParser/Binaries/Win64/UnrealEditor-EasyXMLParser.dll differ diff --git a/Plugins/EasyXMLParser/Binaries/Win64/UnrealEditor-EasyXMLParser.pdb b/Plugins/EasyXMLParser/Binaries/Win64/UnrealEditor-EasyXMLParser.pdb new file mode 100644 index 00000000..594d802e Binary files /dev/null and b/Plugins/EasyXMLParser/Binaries/Win64/UnrealEditor-EasyXMLParser.pdb differ diff --git a/Plugins/EasyXMLParser/Binaries/Win64/UnrealEditor.modules b/Plugins/EasyXMLParser/Binaries/Win64/UnrealEditor.modules new file mode 100644 index 00000000..9485fe35 --- /dev/null +++ b/Plugins/EasyXMLParser/Binaries/Win64/UnrealEditor.modules @@ -0,0 +1,7 @@ +{ + "BuildId": "23058290", + "Modules": + { + "EasyXMLParser": "UnrealEditor-EasyXMLParser.dll" + } +} \ No newline at end of file diff --git a/Plugins/EasyXMLParser/Config/FilterPlugin.ini b/Plugins/EasyXMLParser/Config/FilterPlugin.ini new file mode 100644 index 00000000..ccebca2f --- /dev/null +++ b/Plugins/EasyXMLParser/Config/FilterPlugin.ini @@ -0,0 +1,8 @@ +[FilterPlugin] +; This section lists additional files which will be packaged along with your plugin. Paths should be listed relative to the root plugin directory, and +; may include "...", "*", and "?" wildcards to match directories, files, and individual characters respectively. +; +; Examples: +; /README.txt +; /Extras/... +; /Binaries/ThirdParty/*.dll diff --git a/Plugins/EasyXMLParser/EasyXMLParser.uplugin b/Plugins/EasyXMLParser/EasyXMLParser.uplugin new file mode 100644 index 00000000..39159dc0 --- /dev/null +++ b/Plugins/EasyXMLParser/EasyXMLParser.uplugin @@ -0,0 +1,29 @@ +{ + "FileVersion": 3, + "Version": 1, + "VersionName": "1.0.1", + "FriendlyName": "EasyXMLParser", + "Description": "Parse xml easily", + "Category": "Programming", + "CreatedBy": "ayumax", + "CreatedByURL": "https://github.com/ayumax", + "DocsURL": "https://github.com/ayumax/EasyXMLParserSample", + "MarketplaceURL": "com.epicgames.launcher://ue/marketplace/content/af98110080a4411a8eaf3b8e931b8655", + "SupportURL": "", + "CanContainContent": false, + "IsBetaVersion": false, + "Installed": true, + "Modules": [ + { + "Name": "EasyXMLParser", + "Type": "Runtime", + "LoadingPhase": "Default", + "WhitelistPlatforms": [ + "Android", + "Win64", + "Mac", + "IOS" + ] + } + ] +} \ No newline at end of file diff --git a/Plugins/EasyXMLParser/Resources/Icon128.png b/Plugins/EasyXMLParser/Resources/Icon128.png new file mode 100644 index 00000000..2335a569 Binary files /dev/null and b/Plugins/EasyXMLParser/Resources/Icon128.png differ diff --git a/Plugins/EasyXMLParser/Source/EasyXMLParser/EasyXMLParser.Build.cs b/Plugins/EasyXMLParser/Source/EasyXMLParser/EasyXMLParser.Build.cs new file mode 100644 index 00000000..9578dc48 --- /dev/null +++ b/Plugins/EasyXMLParser/Source/EasyXMLParser/EasyXMLParser.Build.cs @@ -0,0 +1,53 @@ +// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved. + +using UnrealBuildTool; + +public class EasyXMLParser : ModuleRules +{ + public EasyXMLParser(ReadOnlyTargetRules Target) : base(Target) + { + PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; + + PublicIncludePaths.AddRange( + new string[] { + // ... add public include paths required here ... + } + ); + + + PrivateIncludePaths.AddRange( + new string[] { + // ... add other private include paths required here ... + } + ); + + + PublicDependencyModuleNames.AddRange( + new string[] + { + "Core", + // ... add other public dependencies that you statically link with here ... + } + ); + + + PrivateDependencyModuleNames.AddRange( + new string[] + { + "CoreUObject", + "Engine", + "Slate", + "SlateCore", + "XmlParser" + } + ); + + + DynamicallyLoadedModuleNames.AddRange( + new string[] + { + // ... add any modules that your module loads dynamically here ... + } + ); + } +} diff --git a/Plugins/EasyXMLParser/Source/EasyXMLParser/Private/EasyXMLAsyncLoadFromFile.cpp b/Plugins/EasyXMLParser/Source/EasyXMLParser/Private/EasyXMLAsyncLoadFromFile.cpp new file mode 100644 index 00000000..4b214e0f --- /dev/null +++ b/Plugins/EasyXMLParser/Source/EasyXMLParser/Private/EasyXMLAsyncLoadFromFile.cpp @@ -0,0 +1,52 @@ +// Copyright 2019 ayumax. All Rights Reserved. +#include "EasyXMLAsyncLoadFromFile.h" +#include "Engine/World.h" +#include "TimerManager.h" +#include "Async/Async.h" +#include "Utils/CustomXMLParser.h" +#include "EasyXMLParseManager.h" + +UEasyXMLAsyncLoadFromFile::UEasyXMLAsyncLoadFromFile(const FObjectInitializer& ObjectInitializer) + :Super(ObjectInitializer) +{ + +} + +UEasyXMLAsyncLoadFromFile* UEasyXMLAsyncLoadFromFile::AsyncLoadFromFile(UObject* WorldContextObject, const FString& FilePath, bool IsAblolute) +{ + auto Action = NewObject(); + Action->RegisterWithGameInstance(WorldContextObject); + Action->_XMLFile = FilePath; + Action->_IsAblolute = IsAblolute; + + return Action; +} + +void UEasyXMLAsyncLoadFromFile::Activate() +{ + AsyncTask(ENamedThreads::AnyBackgroundThreadNormalTask, [this]() + { + auto manager = NewObject(); + FString _errorMessage; + EEasyXMLParserErrorCode _isSuccessed; + auto rootElement = manager->LoadFromFile(_XMLFile, _IsAblolute, _isSuccessed, _errorMessage); + + if (_isSuccessed == EEasyXMLParserErrorCode::Successed) + { + AsyncTask(ENamedThreads::GameThread, [this, rootElement]() + { + Successed.Broadcast(rootElement, TEXT("")); + SetReadyToDestroy(); + }); + } + else + { + AsyncTask(ENamedThreads::GameThread, [this, _errorMessage]() + { + Failed.Broadcast(nullptr, _errorMessage); + SetReadyToDestroy(); + }); + } + + }); +} diff --git a/Plugins/EasyXMLParser/Source/EasyXMLParser/Private/EasyXMLAsyncLoadFromString.cpp b/Plugins/EasyXMLParser/Source/EasyXMLParser/Private/EasyXMLAsyncLoadFromString.cpp new file mode 100644 index 00000000..3f7a3eaf --- /dev/null +++ b/Plugins/EasyXMLParser/Source/EasyXMLParser/Private/EasyXMLAsyncLoadFromString.cpp @@ -0,0 +1,50 @@ +// Copyright 2019 ayumax. All Rights Reserved. +#include "EasyXMLAsyncLoadFromString.h" +#include "Engine/World.h" +#include "TimerManager.h" +#include "Async/Async.h" +#include "Utils/CustomXMLParser.h" + +UEasyXMLAsyncLoadFromString::UEasyXMLAsyncLoadFromString(const FObjectInitializer& ObjectInitializer) + :Super(ObjectInitializer) +{ + +} + +UEasyXMLAsyncLoadFromString* UEasyXMLAsyncLoadFromString::AsyncLoadFromString(UObject* WorldContextObject, const FString& XMLString) +{ + auto Action = NewObject(); + Action->RegisterWithGameInstance(WorldContextObject); + Action->_XMLString = XMLString; + + return Action; +} + +void UEasyXMLAsyncLoadFromString::Activate() +{ + AsyncTask(ENamedThreads::AnyBackgroundThreadNormalTask, [this]() + { + CustomXMLParser parser; + FString _errorMessage; + + auto rootElement = parser.Parse(_XMLString, _errorMessage); + + if (rootElement != nullptr) + { + AsyncTask(ENamedThreads::GameThread, [this, rootElement]() + { + Successed.Broadcast(rootElement, TEXT("")); + SetReadyToDestroy(); + }); + } + else + { + AsyncTask(ENamedThreads::GameThread, [this, _errorMessage]() + { + Failed.Broadcast(nullptr, _errorMessage); + SetReadyToDestroy(); + }); + } + + }); +} diff --git a/Plugins/EasyXMLParser/Source/EasyXMLParser/Private/EasyXMLAttribute.cpp b/Plugins/EasyXMLParser/Source/EasyXMLParser/Private/EasyXMLAttribute.cpp new file mode 100644 index 00000000..19061b5f --- /dev/null +++ b/Plugins/EasyXMLParser/Source/EasyXMLParser/Private/EasyXMLAttribute.cpp @@ -0,0 +1,13 @@ +// Copyright 2019 ayumax. All Rights Reserved. +#include "EasyXMLAttribute.h" +#include "EasyXMLElement.h" + +UEasyXMLAttribute* UEasyXMLAttribute::CreateAttribute(UEasyXMLElement* ParentObject, FString _Name, FString _Value) +{ + auto newAttribute = NewObject(ParentObject == nullptr ? (UObject*)GetTransientPackage() : ParentObject); + newAttribute->Parent = ParentObject; + newAttribute->Name = _Name; + newAttribute->Value = _Value.TrimStartAndEnd(); + + return newAttribute; +} \ No newline at end of file diff --git a/Plugins/EasyXMLParser/Source/EasyXMLParser/Private/EasyXMLElement.cpp b/Plugins/EasyXMLParser/Source/EasyXMLParser/Private/EasyXMLElement.cpp new file mode 100644 index 00000000..d8878cce --- /dev/null +++ b/Plugins/EasyXMLParser/Source/EasyXMLParser/Private/EasyXMLElement.cpp @@ -0,0 +1,223 @@ +// Copyright 2019 ayumax. All Rights Reserved. +#include "EasyXMLElement.h" +#include "EasyXMLAttribute.h" +#include "Internationalization/Regex.h" + +UEasyXMLElement* UEasyXMLElement::CreateElement(UEasyXMLObject* ParentObject, FString Tag, FString Content, int32 _LineNumber) +{ + auto newElement = NewObject(ParentObject == nullptr ? (UObject*)GetTransientPackage() : ParentObject); + newElement->Parent = ParentObject; + newElement->Name = Tag; + newElement->Value = Content.TrimStartAndEnd(); + newElement->LineNumber = _LineNumber; + + return newElement; +} + + +int32 UEasyXMLElement::ReadInt(const FString& AccessString, int32 DefaultValue) +{ + auto foundElement = ReadEasyXMLObject(AccessString); + if (!foundElement) return DefaultValue; + + return foundElement->GetIntValue(DefaultValue); +} + + +float UEasyXMLElement::ReadFloat(const FString& AccessString, float DefaultValue) +{ + auto foundElement = ReadEasyXMLObject(AccessString); + if (!foundElement) return DefaultValue; + + return foundElement->GetFloatValue(DefaultValue); +} + +FString UEasyXMLElement::ReadString(const FString& AccessString, const FString& DefaultValue) +{ + auto foundElement = ReadEasyXMLObject(AccessString); + if (!foundElement) return DefaultValue; + + return foundElement->GetStringValue(DefaultValue); +} + +bool UEasyXMLElement::ReadBool(const FString& AccessString, bool DefaultValue) +{ + auto foundElement = ReadEasyXMLObject(AccessString); + if (!foundElement) return DefaultValue; + + return foundElement->GetBoolValue(DefaultValue); +} + +UEasyXMLElement* UEasyXMLElement::ReadElement(const FString& AccessString, EEasyXMLParserFound& Result) +{ + auto filterArray = ReadElements(AccessString, Result); + + return filterArray.Num() > 0 ? filterArray[0] : nullptr; +} + +TArray UEasyXMLElement::ReadElements(const FString& AccessString, EEasyXMLParserFound& Result) +{ + TArray foundElements; + + TArray Accessers; + AccessString.ParseIntoArray(Accessers, TEXT("."), true); + + Result = EEasyXMLParserFound::NotFound; + + auto parentNode = this; + + for (int i = 0; i < Accessers.Num(); ++i) + { + auto accesseName = Accessers[i]; + + if (accesseName.IsEmpty()) return foundElements; + + if (accesseName[0] == TEXT('@')) + { + return foundElements; + } + + FString elementName; + int32 arrayIndex = 0; + bool IsArrayAccess = IsAccessAsArray(accesseName, elementName, arrayIndex); + + auto filterNodes = parentNode->GetElementsByTagName(elementName); + + if (i == (Accessers.Num() - 1)) + { + if (IsArrayAccess) + { + if (filterNodes.Num() > arrayIndex) + { + foundElements.Emplace(filterNodes[arrayIndex]); + } + } + else + { + foundElements = filterNodes; + } + } + else + { + if (filterNodes.Num() > arrayIndex) + { + parentNode = filterNodes[arrayIndex]; + } + + if (!parentNode) return foundElements; + } + } + + Result = EEasyXMLParserFound::Found; + + return foundElements; +} + +UEasyXMLObject* UEasyXMLElement::ReadEasyXMLObject(const FString& AccessString) +{ + TArray Accessers; + AccessString.ParseIntoArray(Accessers, TEXT("."), true); + + auto parentNode = this; + + for (auto accesseName : Accessers) + { + if (!parentNode) return nullptr; + if (accesseName.IsEmpty()) return nullptr; + + if (accesseName[0] == TEXT('@')) + { + EEasyXMLParserFound retFound; + return parentNode->GetAttribute(accesseName.Mid(1), retFound); + } + + FString elementName; + int32 arrayIndex = 0; + IsAccessAsArray(accesseName, elementName, arrayIndex); + + auto filterNodes = parentNode->GetElementsByTagName(elementName); + if (filterNodes.Num() > arrayIndex) + { + parentNode = filterNodes[arrayIndex]; + } + else + { + return nullptr; + } + } + + return parentNode; +} + +TArray UEasyXMLElement::GetElementsByTagName(const FString& TagName) +{ + TArray foundElements = Children.FilterByPredicate( + [TagName](UEasyXMLElement* child) + { + return child->Name.Equals(TagName, ESearchCase::IgnoreCase); + }); + + return foundElements; +} + +UEasyXMLAttribute* UEasyXMLElement::GetAttribute(const FString& AtrributeName, EEasyXMLParserFound& Result) +{ + if (Attributes.Contains(AtrributeName)) + { + Result = EEasyXMLParserFound::Found; + return Attributes[AtrributeName]; + } + + Result = EEasyXMLParserFound::NotFound; + return nullptr; +} + +bool UEasyXMLElement::IsAccessAsArray(const FString& AccessName, FString& ElementName, int32& ArrayIndex) +{ + const FRegexPattern pattern = FRegexPattern(FString(TEXT("(.*)\\[([0-9]+)\\]$"))); + FRegexMatcher matcher(pattern, AccessName); + + while (matcher.FindNext()) + { + ElementName = matcher.GetCaptureGroup(1); + + FString numStr = matcher.GetCaptureGroup(2); + if (numStr.IsNumeric()) + { + ArrayIndex = (FCString::Atoi(*numStr)); + } + + return true; + } + + ElementName = AccessName; + ArrayIndex = 0; + + return false; +} + + + +bool UEasyXMLElement::IsContainAttributeKeys(const TArray& Keys, TArray& FoundAttributeKeys) +{ + TArray attributeKeys; + Attributes.GetKeys(attributeKeys); + + for (auto key : Keys) + { + bool found = false; + for (auto attributeKey : attributeKeys) + { + if (key.Equals(attributeKey, ESearchCase::IgnoreCase)) + { + found = true; + FoundAttributeKeys.Emplace(attributeKey); + } + + } + + if (!found) return false; + } + + return true; +} diff --git a/Plugins/EasyXMLParser/Source/EasyXMLParser/Private/EasyXMLObject.cpp b/Plugins/EasyXMLParser/Source/EasyXMLParser/Private/EasyXMLObject.cpp new file mode 100644 index 00000000..7529b009 --- /dev/null +++ b/Plugins/EasyXMLParser/Source/EasyXMLParser/Private/EasyXMLObject.cpp @@ -0,0 +1,49 @@ +// Copyright 2019 ayumax. All Rights Reserved. + +#include "EasyXMLObject.h" +#include "Utils/CustomXMLParser.h" + +int32 UEasyXMLObject::GetIntValue(int32 DefaultValue) +{ + if (Value.IsEmpty()) return DefaultValue; + + int32 _index = 0; + + if (Value.IsNumeric() && !Value.FindChar(TEXT('.'), _index)) + { + return FCString::Atoi(*Value); + } + + return DefaultValue; +} + +float UEasyXMLObject::GetFloatValue(float DefaultValue) +{ + if (Value.IsEmpty()) return DefaultValue; + + auto isSuccess = Value.IsNumeric(); + return isSuccess ? FCString::Atof(*Value) : DefaultValue; +} + +FString UEasyXMLObject::GetStringValue(FString DefaultValue) +{ + if (Value.IsEmpty()) return DefaultValue; + + return Value; +} + +bool UEasyXMLObject::GetBoolValue(bool DefaultValue) +{ + if (Value.IsEmpty()) return DefaultValue; + + if (Value.Equals(TEXT("true"), ESearchCase::IgnoreCase)) + { + return true; + } + else if (Value.Equals(TEXT("false"), ESearchCase::IgnoreCase)) + { + return false; + } + + return DefaultValue; +} diff --git a/Plugins/EasyXMLParser/Source/EasyXMLParser/Private/EasyXMLParseManager.cpp b/Plugins/EasyXMLParser/Source/EasyXMLParser/Private/EasyXMLParseManager.cpp new file mode 100644 index 00000000..a2a24c69 --- /dev/null +++ b/Plugins/EasyXMLParser/Source/EasyXMLParser/Private/EasyXMLParseManager.cpp @@ -0,0 +1,37 @@ +// Copyright 2019 ayumax. All Rights Reserved. + +#include "EasyXMLParseManager.h" +#include "Misc/Paths.h" +#include "Misc/FileHelper.h" +#include "EasyXMLElement.h" +#include "Utils/CustomXMLParser.h" + + +UEasyXMLElement* UEasyXMLParseManager::LoadFromString(const FString& XMLString, EEasyXMLParserErrorCode& Result, FString& ErrorMessage) +{ + CustomXMLParser parser; + FString _errorMessage; + + auto rootElement = parser.Parse(XMLString, _errorMessage); + Result = rootElement != nullptr ? EEasyXMLParserErrorCode::Successed : EEasyXMLParserErrorCode::Failed; + ErrorMessage = _errorMessage; + + return rootElement; +} + +UEasyXMLElement* UEasyXMLParseManager::LoadFromFile(const FString& FilePath, bool IsAblolute, EEasyXMLParserErrorCode& Result, FString& ErrorMessage) +{ + auto readPath = FilePath; + if (!IsAblolute) + { + readPath = FPaths::Combine(FPaths::ProjectContentDir(), FilePath); + } + + if (!FPaths::FileExists(readPath)) return nullptr; + + FString xmlString; + + FFileHelper::LoadFileToString(xmlString, *readPath); + + return LoadFromString(xmlString, Result, ErrorMessage); +} diff --git a/Plugins/EasyXMLParser/Source/EasyXMLParser/Private/EasyXMLParser.cpp b/Plugins/EasyXMLParser/Source/EasyXMLParser/Private/EasyXMLParser.cpp new file mode 100644 index 00000000..80f860da --- /dev/null +++ b/Plugins/EasyXMLParser/Source/EasyXMLParser/Private/EasyXMLParser.cpp @@ -0,0 +1,20 @@ +// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved. + +#include "EasyXMLParser.h" + +#define LOCTEXT_NAMESPACE "FEasyXMLParserModule" + +void FEasyXMLParserModule::StartupModule() +{ + // This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module +} + +void FEasyXMLParserModule::ShutdownModule() +{ + // This function may be called during shutdown to clean up your module. For modules that support dynamic reloading, + // we call this function before unloading the module. +} + +#undef LOCTEXT_NAMESPACE + +IMPLEMENT_MODULE(FEasyXMLParserModule, EasyXMLParser) \ No newline at end of file diff --git a/Plugins/EasyXMLParser/Source/EasyXMLParser/Private/Tests/NodeAccessTest.cpp b/Plugins/EasyXMLParser/Source/EasyXMLParser/Private/Tests/NodeAccessTest.cpp new file mode 100644 index 00000000..83ec705d --- /dev/null +++ b/Plugins/EasyXMLParser/Source/EasyXMLParser/Private/Tests/NodeAccessTest.cpp @@ -0,0 +1,270 @@ +// Copyright 2019 ayumax. All Rights Reserved. +#include "Misc/AutomationTest.h" +#include "EasyXMLParseManager.h" + +IMPLEMENT_SIMPLE_AUTOMATION_TEST(FNodeAccessTest, "EasyXMLParser.NodeAccessTest", EAutomationTestFlags::ApplicationContextMask | EAutomationTestFlags::SmokeFilter) + +bool FNodeAccessTest::RunTest(const FString& Parameters) +{ + { + FString xmlString = TEXT("\r") + TEXT("\r") + TEXT("\r") + TEXT("123\r") + TEXT("\r") + TEXT("\r") + TEXT("40\r") + TEXT("ZZZZ\r") + TEXT("\r") + TEXT("bbbChild\r") + TEXT("\r") + TEXT(""); + + EEasyXMLParserErrorCode result; + FString errorMessage; + auto rootNode = UEasyXMLParseManager::LoadFromString(xmlString, result, errorMessage); + + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("root.abc")), TEXT("123")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("root.abc[0]")), TEXT("123")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("root.abc[1]")), TEXT("")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("root.abc[2]")), TEXT("40")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("root.abc[3]")), TEXT("ZZZZ")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("root.bbb")), TEXT("bbbChild")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("root.abc[0].@attr1")), TEXT("10")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("root.abc[0].@attr2")), TEXT("false")); + } + + return true; +} + + +IMPLEMENT_SIMPLE_AUTOMATION_TEST(FNodeAccessTest2, "EasyXMLParser.NodeAccessTest2", EAutomationTestFlags::ApplicationContextMask | EAutomationTestFlags::SmokeFilter) + +bool FNodeAccessTest2::RunTest(const FString& Parameters) +{ + FString XMLSource = + TEXT("\r") + TEXT("
\r") + TEXT("Ellen Adams\r") + TEXT("123 Maple Street\r") + TEXT("Mill Valley\r") + TEXT("CA\r") + TEXT("10999\r") + TEXT("USA\r") + TEXT("
\r") + TEXT("
\r") + TEXT("Tai Yee\r") + TEXT("8 Oak Avenue\r") + TEXT("Old Town\r") + TEXT("PA\r") + TEXT("95819\r") + TEXT("USA\r") + TEXT("
\r") + TEXT("Please leave packages in shed by driveway.\r") + TEXT("\r") + TEXT("\r") + TEXT("Lawnmower\r") + TEXT("1\r") + TEXT("148.95\r") + TEXT("Confirm this is electric\r") + TEXT("\r") + TEXT("\r") + TEXT("Baby Monitor\r") + TEXT("2\r") + TEXT("39.98\r") + TEXT("1999-05-21\r") + TEXT("\r") + TEXT("\r") + TEXT("
\r"); + + { + EEasyXMLParserErrorCode result; + FString errorMessage; + auto rootNode = UEasyXMLParseManager::LoadFromString(XMLSource, result, errorMessage); + + TestEqual(TEXT("success read"), rootNode->ReadInt(TEXT("PurchaseOrder.@PurchaseOrderNumber")), 99503); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.@OrderDate")), TEXT("1999-10-20")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.Address[0].@Type")), TEXT("Shipping")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.Address[0].Name")), TEXT("Ellen Adams")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.Address[0].Street")), TEXT("123 Maple Street")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.Address[0].City")), TEXT("Mill Valley")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.Address[0].State")), TEXT("CA")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.Address[0].Zip")), TEXT("10999")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.Address[0].Country")), TEXT("USA")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.Address[1].@Type")), TEXT("Billing")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.Address[1].Name")), TEXT("Tai Yee")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.Address[1].Street")), TEXT("8 Oak Avenue")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.Address[1].City")), TEXT("Old Town")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.Address[1].State")), TEXT("PA")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.Address[1].Zip")), TEXT("95819")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.Address[1].Country")), TEXT("USA")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.DeliveryNotes")), TEXT("Please leave packages in shed by driveway.")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.Items.Item[0].@PartNumber")), TEXT("872-AA")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.Items.Item[0].ProductName")), TEXT("Lawnmower")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.Items.Item[0].Quantity")), TEXT("1")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.Items.Item[0].USPrice")), TEXT("148.95")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.Items.Item[0].Comment")), TEXT("Confirm this is electric")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.Items.Item[1].@PartNumber")), TEXT("926-AA")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.Items.Item[1].ProductName")), TEXT("Baby Monitor")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.Items.Item[1].Quantity")), TEXT("2")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.Items.Item[1].USPrice")), TEXT("39.98")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.Items.Item[1].ShipDate")), TEXT("1999-05-21")); + } + + { + EEasyXMLParserErrorCode result; + FString errorMessage; + auto rootNode = UEasyXMLParseManager::LoadFromString(XMLSource, result, errorMessage); + + EEasyXMLParserFound retFound; + auto Address0Node = rootNode->ReadElement(TEXT("PurchaseOrder.Address[0]"), retFound); + TestTrue(TEXT("success read"), retFound == EEasyXMLParserFound::Found); + auto Address1Node = rootNode->ReadElement(TEXT("PurchaseOrder.Address[1]"), retFound); + TestTrue(TEXT("success read"), retFound == EEasyXMLParserFound::Found); + auto Item0Node = rootNode->ReadElement(TEXT("PurchaseOrder.Items.Item[0]"), retFound); + TestTrue(TEXT("success read"), retFound == EEasyXMLParserFound::Found); + auto Item1Node = rootNode->ReadElement(TEXT("PurchaseOrder.Items.Item[1]"), retFound); + TestTrue(TEXT("success read"), retFound == EEasyXMLParserFound::Found); + + TestEqual(TEXT("success read"), rootNode->ReadInt(TEXT("PurchaseOrder.@PurchaseOrderNumber")), 99503); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.@OrderDate")), TEXT("1999-10-20")); + TestEqual(TEXT("success read"), Address0Node->ReadString(TEXT("@Type")), TEXT("Shipping")); + TestEqual(TEXT("success read"), Address0Node->ReadString(TEXT("Name")), TEXT("Ellen Adams")); + TestEqual(TEXT("success read"), Address0Node->ReadString(TEXT("Street")), TEXT("123 Maple Street")); + TestEqual(TEXT("success read"), Address0Node->ReadString(TEXT("City")), TEXT("Mill Valley")); + TestEqual(TEXT("success read"), Address0Node->ReadString(TEXT("State")), TEXT("CA")); + TestEqual(TEXT("success read"), Address0Node->ReadString(TEXT("Zip")), TEXT("10999")); + TestEqual(TEXT("success read"), Address0Node->ReadString(TEXT("Country")), TEXT("USA")); + TestEqual(TEXT("success read"), Address1Node->ReadString(TEXT("@Type")), TEXT("Billing")); + TestEqual(TEXT("success read"), Address1Node->ReadString(TEXT("Name")), TEXT("Tai Yee")); + TestEqual(TEXT("success read"), Address1Node->ReadString(TEXT("Street")), TEXT("8 Oak Avenue")); + TestEqual(TEXT("success read"), Address1Node->ReadString(TEXT("City")), TEXT("Old Town")); + TestEqual(TEXT("success read"), Address1Node->ReadString(TEXT("State")), TEXT("PA")); + TestEqual(TEXT("success read"), Address1Node->ReadString(TEXT("Zip")), TEXT("95819")); + TestEqual(TEXT("success read"), Address1Node->ReadString(TEXT("Country")), TEXT("USA")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.DeliveryNotes")), TEXT("Please leave packages in shed by driveway.")); + TestEqual(TEXT("success read"), Item0Node->ReadString(TEXT("@PartNumber")), TEXT("872-AA")); + TestEqual(TEXT("success read"), Item0Node->ReadString(TEXT("ProductName")), TEXT("Lawnmower")); + TestEqual(TEXT("success read"), Item0Node->ReadString(TEXT("Quantity")), TEXT("1")); + TestEqual(TEXT("success read"), Item0Node->ReadString(TEXT("USPrice")), TEXT("148.95")); + TestEqual(TEXT("success read"), Item0Node->ReadString(TEXT("Comment")), TEXT("Confirm this is electric")); + TestEqual(TEXT("success read"), Item1Node->ReadString(TEXT("@PartNumber")), TEXT("926-AA")); + TestEqual(TEXT("success read"), Item1Node->ReadString(TEXT("ProductName")), TEXT("Baby Monitor")); + TestEqual(TEXT("success read"), Item1Node->ReadString(TEXT("Quantity")), TEXT("2")); + TestEqual(TEXT("success read"), Item1Node->ReadString(TEXT("USPrice")), TEXT("39.98")); + TestEqual(TEXT("success read"), Item1Node->ReadString(TEXT("ShipDate")), TEXT("1999-05-21")); + } + + + { + EEasyXMLParserErrorCode result; + FString errorMessage; + auto rootNode = UEasyXMLParseManager::LoadFromString(XMLSource, result, errorMessage); + + EEasyXMLParserFound retFound; + auto AddressNodes = rootNode->ReadElements(TEXT("PurchaseOrder.Address"), retFound); + TestTrue(TEXT("success read"), retFound == EEasyXMLParserFound::Found); + auto ItemNodes = rootNode->ReadElements(TEXT("PurchaseOrder.Items.Item"), retFound); + TestTrue(TEXT("success read"), retFound == EEasyXMLParserFound::Found); + + TestEqual(TEXT("success read"), AddressNodes[0]->ReadString(TEXT("@Type")), TEXT("Shipping")); + TestEqual(TEXT("success read"), AddressNodes[0]->ReadString(TEXT("Name")), TEXT("Ellen Adams")); + TestEqual(TEXT("success read"), AddressNodes[0]->ReadString(TEXT("Street")), TEXT("123 Maple Street")); + TestEqual(TEXT("success read"), AddressNodes[0]->ReadString(TEXT("City")), TEXT("Mill Valley")); + TestEqual(TEXT("success read"), AddressNodes[0]->ReadString(TEXT("State")), TEXT("CA")); + TestEqual(TEXT("success read"), AddressNodes[0]->ReadString(TEXT("Zip")), TEXT("10999")); + TestEqual(TEXT("success read"), AddressNodes[0]->ReadString(TEXT("Country")), TEXT("USA")); + TestEqual(TEXT("success read"), AddressNodes[1]->ReadString(TEXT("@Type")), TEXT("Billing")); + TestEqual(TEXT("success read"), AddressNodes[1]->ReadString(TEXT("Name")), TEXT("Tai Yee")); + TestEqual(TEXT("success read"), AddressNodes[1]->ReadString(TEXT("Street")), TEXT("8 Oak Avenue")); + TestEqual(TEXT("success read"), AddressNodes[1]->ReadString(TEXT("City")), TEXT("Old Town")); + TestEqual(TEXT("success read"), AddressNodes[1]->ReadString(TEXT("State")), TEXT("PA")); + TestEqual(TEXT("success read"), AddressNodes[1]->ReadString(TEXT("Zip")), TEXT("95819")); + TestEqual(TEXT("success read"), AddressNodes[1]->ReadString(TEXT("Country")), TEXT("USA")); + + TestEqual(TEXT("success read"), ItemNodes[0]->ReadString(TEXT("@PartNumber")), TEXT("872-AA")); + TestEqual(TEXT("success read"), ItemNodes[0]->ReadString(TEXT("ProductName")), TEXT("Lawnmower")); + TestEqual(TEXT("success read"), ItemNodes[0]->ReadString(TEXT("Quantity")), TEXT("1")); + TestEqual(TEXT("success read"), ItemNodes[0]->ReadString(TEXT("USPrice")), TEXT("148.95")); + TestEqual(TEXT("success read"), ItemNodes[0]->ReadString(TEXT("Comment")), TEXT("Confirm this is electric")); + TestEqual(TEXT("success read"), ItemNodes[1]->ReadString(TEXT("@PartNumber")), TEXT("926-AA")); + TestEqual(TEXT("success read"), ItemNodes[1]->ReadString(TEXT("ProductName")), TEXT("Baby Monitor")); + TestEqual(TEXT("success read"), ItemNodes[1]->ReadString(TEXT("Quantity")), TEXT("2")); + TestEqual(TEXT("success read"), ItemNodes[1]->ReadString(TEXT("USPrice")), TEXT("39.98")); + TestEqual(TEXT("success read"), ItemNodes[1]->ReadString(TEXT("ShipDate")), TEXT("1999-05-21")); + } + + { + EEasyXMLParserErrorCode result; + FString errorMessage; + auto rootNode = UEasyXMLParseManager::LoadFromString(XMLSource, result, errorMessage); + + TestEqual(TEXT("success read"), rootNode->ReadInt(TEXT("PurchaseOrder.PurchaseOrderNumber")), 0); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.OrderDate")), TEXT("")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.Address[0].Type")), TEXT("")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.Address[0].Name-")), TEXT("")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrde-r.Address[0].Street")), TEXT("")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.Address-[0].City")), TEXT("")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.Address[0].State-")), TEXT("")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder-.Address[0].Zip")), TEXT("")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.Address[0]-.Country")), TEXT("")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.Address[1]-.@Type")), TEXT("")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder-.Address[1].Name")), TEXT("")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.Address[1].Stree-t")), TEXT("")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.Address[1]-.City")), TEXT("")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder-.Address[1].State")), TEXT("")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.Address[1].Zip-")), TEXT("")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.Address[1]-.Country")), TEXT("")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder-.DeliveryNotes")), TEXT("")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.Items.Item[0].@PartNumber-")), TEXT("")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.Items.Item[0]-.ProductName")), TEXT("")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.Items-.Item[0].Quantity")), TEXT("")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.Items.Item[4].USPrice")), TEXT("")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.Items.Item[-1].Comment")), TEXT("")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.Items.Item[8].@PartNumber")), TEXT("")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.Items.Item[99].ProductName")), TEXT("")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.Items.Item[7].Quantity")), TEXT("")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.Items.Item[555].USPrice")), TEXT("")); + TestEqual(TEXT("success read"), rootNode->ReadString(TEXT("PurchaseOrder.Items.Item[9999].ShipDate")), TEXT("")); + } + + { + EEasyXMLParserErrorCode result; + FString errorMessage; + auto rootNode = UEasyXMLParseManager::LoadFromString(XMLSource, result, errorMessage); + + EEasyXMLParserFound retFound; + auto AddressNodes = rootNode->ReadElements(TEXT("PurchaseOrder.Address"), retFound); + TestTrue(TEXT("success read"), retFound == EEasyXMLParserFound::Found); + auto ItemNodes = rootNode->ReadElements(TEXT("PurchaseOrder.Items.Item"), retFound); + TestTrue(TEXT("success read"), retFound == EEasyXMLParserFound::Found); + + TestEqual(TEXT("success read"), AddressNodes[0]->ReadString(TEXT("@Type-")), TEXT("")); + TestEqual(TEXT("success read"), AddressNodes[0]->ReadString(TEXT("Name-")), TEXT("")); + TestEqual(TEXT("success read"), AddressNodes[0]->ReadString(TEXT("Street-")), TEXT("")); + TestEqual(TEXT("success read"), AddressNodes[0]->ReadString(TEXT("City-")), TEXT("")); + TestEqual(TEXT("success read"), AddressNodes[0]->ReadString(TEXT("State-")), TEXT("")); + TestEqual(TEXT("success read"), AddressNodes[0]->ReadString(TEXT("Zip-")), TEXT("")); + TestEqual(TEXT("success read"), AddressNodes[0]->ReadString(TEXT("Country-")), TEXT("")); + TestEqual(TEXT("success read"), AddressNodes[1]->ReadString(TEXT("@Type-")), TEXT("")); + TestEqual(TEXT("success read"), AddressNodes[1]->ReadString(TEXT("Name-")), TEXT("")); + TestEqual(TEXT("success read"), AddressNodes[1]->ReadString(TEXT("Street-")), TEXT("")); + TestEqual(TEXT("success read"), AddressNodes[1]->ReadString(TEXT("City-")), TEXT("")); + TestEqual(TEXT("success read"), AddressNodes[1]->ReadString(TEXT("State-")), TEXT("")); + TestEqual(TEXT("success read"), AddressNodes[1]->ReadString(TEXT("Zip-")), TEXT("")); + TestEqual(TEXT("success read"), AddressNodes[1]->ReadString(TEXT("Country-")), TEXT("")); + + TestEqual(TEXT("success read"), ItemNodes[0]->ReadString(TEXT("@PartNumber-")), TEXT("")); + TestEqual(TEXT("success read"), ItemNodes[0]->ReadString(TEXT("ProductName-")), TEXT("")); + TestEqual(TEXT("success read"), ItemNodes[0]->ReadString(TEXT("Quantity-")), TEXT("")); + TestEqual(TEXT("success read"), ItemNodes[0]->ReadString(TEXT("USPrice-")), TEXT("")); + TestEqual(TEXT("success read"), ItemNodes[0]->ReadString(TEXT("Comment-")), TEXT("")); + TestEqual(TEXT("success read"), ItemNodes[1]->ReadString(TEXT("@PartNumber-")), TEXT("")); + TestEqual(TEXT("success read"), ItemNodes[1]->ReadString(TEXT("ProductName-")), TEXT("")); + TestEqual(TEXT("success read"), ItemNodes[1]->ReadString(TEXT("Quantity-")), TEXT("")); + TestEqual(TEXT("success read"), ItemNodes[1]->ReadString(TEXT("USPrice-")), TEXT("")); + TestEqual(TEXT("success read"), ItemNodes[1]->ReadString(TEXT("ShipDate-")), TEXT("")); + } + + return true; +} \ No newline at end of file diff --git a/Plugins/EasyXMLParser/Source/EasyXMLParser/Private/Tests/ReadValueTest.cpp b/Plugins/EasyXMLParser/Source/EasyXMLParser/Private/Tests/ReadValueTest.cpp new file mode 100644 index 00000000..8a755649 --- /dev/null +++ b/Plugins/EasyXMLParser/Source/EasyXMLParser/Private/Tests/ReadValueTest.cpp @@ -0,0 +1,428 @@ +// Copyright 2019 ayumax. All Rights Reserved. +#include "Misc/AutomationTest.h" +#include "EasyXMLParseManager.h" + +IMPLEMENT_SIMPLE_AUTOMATION_TEST(FReadValueTest_Int, "EasyXMLParser.ReadValueTest.Int", EAutomationTestFlags::ApplicationContextMask | EAutomationTestFlags::SmokeFilter) + +bool FReadValueTest_Int::RunTest(const FString& Parameters) +{ + // parse success + { + FString xmlString = TEXT("\r") + TEXT("\r") + TEXT("\r") + TEXT("123\r") + TEXT("\r") + TEXT(""); + + EEasyXMLParserErrorCode result; + FString errorMessage; + auto rootNode = UEasyXMLParseManager::LoadFromString(xmlString, result, errorMessage); + + TestEqual(TEXT("success read int"), rootNode->ReadInt(TEXT("root.abc"), 0), 123); + } + + // parse success + { + FString xmlString = TEXT("") + TEXT("") + TEXT("-123") + TEXT("") + TEXT(""); + + EEasyXMLParserErrorCode result; + FString errorMessage; + auto rootNode = UEasyXMLParseManager::LoadFromString(xmlString, result, errorMessage); + + TestEqual(TEXT("success read int"), rootNode->ReadInt(TEXT("root.abc"), 0), -123); + } + + // parse success + { + FString xmlString = TEXT("") + TEXT("") + TEXT("123456789") + TEXT("") + TEXT(""); + + EEasyXMLParserErrorCode result; + FString errorMessage; + auto rootNode = UEasyXMLParseManager::LoadFromString(xmlString, result, errorMessage); + + + TestEqual(TEXT("success read int"), rootNode->ReadInt(TEXT("root.abc"), 0), 123456789); + } + + + // parse ng(string) + { + FString xmlString = TEXT("") + TEXT("") + TEXT("text") + TEXT("") + TEXT(""); + + EEasyXMLParserErrorCode result; + FString errorMessage; + auto rootNode = UEasyXMLParseManager::LoadFromString(xmlString, result, errorMessage); + + + TestEqual(TEXT("ng read int(string)"), rootNode->ReadInt(TEXT("root.abc"), 0), 0); + } + + // parse ng(float) + { + FString xmlString = TEXT("") + TEXT("") + TEXT("3.14") + TEXT("") + TEXT(""); + + EEasyXMLParserErrorCode result; + FString errorMessage; + auto rootNode = UEasyXMLParseManager::LoadFromString(xmlString, result, errorMessage); + + + TestEqual(TEXT("ng read int(float)"), rootNode->ReadInt(TEXT("root.abc"), 0), 0); + } + + // parse ng(xml) + { + FString xmlString = TEXT("") + TEXT("") + TEXT("") + TEXT("123") + TEXT("") + TEXT("") + TEXT(""); + + EEasyXMLParserErrorCode result; + FString errorMessage; + auto rootNode = UEasyXMLParseManager::LoadFromString(xmlString, result, errorMessage); + + + TestEqual(TEXT("ng read int(xml)"), rootNode->ReadInt(TEXT("root.abc"), 0), 0); + } + + + return true; +} + + +IMPLEMENT_SIMPLE_AUTOMATION_TEST(FReadValueTest_Float, "EasyXMLParser.ReadValueTest.Float", EAutomationTestFlags::ApplicationContextMask | EAutomationTestFlags::SmokeFilter) + +bool FReadValueTest_Float::RunTest(const FString& Parameters) +{ + // parse success + { + FString xmlString = TEXT("") + TEXT("") + TEXT("1.23") + TEXT("") + TEXT(""); + + EEasyXMLParserErrorCode result; + FString errorMessage; + auto rootNode = UEasyXMLParseManager::LoadFromString(xmlString, result, errorMessage); + + + TestEqual(TEXT("success read float"), rootNode->ReadFloat(TEXT("root.abc"), 0), 1.23f); + } + + // parse success + { + FString xmlString = TEXT("") + TEXT("") + TEXT("-1.23") + TEXT("") + TEXT(""); + + EEasyXMLParserErrorCode result; + FString errorMessage; + auto rootNode = UEasyXMLParseManager::LoadFromString(xmlString, result, errorMessage); + + + TestEqual(TEXT("success read float"), rootNode->ReadFloat(TEXT("root.abc"), 0), -1.23f); + } + + // parse success + { + FString xmlString = TEXT("") + TEXT("") + TEXT("123.456789") + TEXT("") + TEXT(""); + + EEasyXMLParserErrorCode result; + FString errorMessage; + auto rootNode = UEasyXMLParseManager::LoadFromString(xmlString, result, errorMessage); + + + TestEqual(TEXT("success read float"), rootNode->ReadFloat(TEXT("root.abc"), 0), 123.456789f); + } + + // parse success + { + FString xmlString = TEXT("") + TEXT("") + TEXT("123") + TEXT("") + TEXT(""); + + EEasyXMLParserErrorCode result; + FString errorMessage; + auto rootNode = UEasyXMLParseManager::LoadFromString(xmlString, result, errorMessage); + + + TestEqual(TEXT("success read float"), rootNode->ReadFloat(TEXT("root.abc"), 0), 123.0f); + } + + + // parse ng(string) + { + FString xmlString = TEXT("") + TEXT("") + TEXT("text") + TEXT("") + TEXT(""); + + EEasyXMLParserErrorCode result; + FString errorMessage; + auto rootNode = UEasyXMLParseManager::LoadFromString(xmlString, result, errorMessage); + + + TestEqual(TEXT("ng read float(string)"), rootNode->ReadFloat(TEXT("root.abc"), 0), 0.0f); + } + + // parse ng(xml) + { + FString xmlString = TEXT("") + TEXT("") + TEXT("") + TEXT("1.23") + TEXT("") + TEXT("") + TEXT(""); + + EEasyXMLParserErrorCode result; + FString errorMessage; + auto rootNode = UEasyXMLParseManager::LoadFromString(xmlString, result, errorMessage); + + + TestEqual(TEXT("ng read float(xml)"), rootNode->ReadFloat(TEXT("root.abc"), 0), 0.0f); + } + + return true; +} + + +IMPLEMENT_SIMPLE_AUTOMATION_TEST(FReadValueTest_Bool, "EasyXMLParser.ReadValueTest.Bool", EAutomationTestFlags::ApplicationContextMask | EAutomationTestFlags::SmokeFilter) + +bool FReadValueTest_Bool::RunTest(const FString& Parameters) +{ + // parse success + { + FString xmlString = TEXT("") + TEXT("") + TEXT("True") + TEXT("") + TEXT(""); + + EEasyXMLParserErrorCode result; + FString errorMessage; + auto rootNode = UEasyXMLParseManager::LoadFromString(xmlString, result, errorMessage); + + + TestEqual(TEXT("success read bool"), rootNode->ReadBool(TEXT("root.abc"), false), true); + } + + // parse success + { + FString xmlString = TEXT("") + TEXT("") + TEXT("tRue") + TEXT("") + TEXT(""); + + EEasyXMLParserErrorCode result; + FString errorMessage; + auto rootNode = UEasyXMLParseManager::LoadFromString(xmlString, result, errorMessage); + + + TestEqual(TEXT("success read bool"), rootNode->ReadBool(TEXT("root.abc"), false), true); + } + + // parse success + { + FString xmlString = TEXT("") + TEXT("") + TEXT("False") + TEXT("") + TEXT(""); + + EEasyXMLParserErrorCode result; + FString errorMessage; + auto rootNode = UEasyXMLParseManager::LoadFromString(xmlString, result, errorMessage); + + + TestEqual(TEXT("success read bool"), rootNode->ReadBool(TEXT("root.abc"), true), false); + } + + // parse success + { + FString xmlString = TEXT("") + TEXT("") + TEXT("fAlse") + TEXT("") + TEXT(""); + + EEasyXMLParserErrorCode result; + FString errorMessage; + auto rootNode = UEasyXMLParseManager::LoadFromString(xmlString, result, errorMessage); + + + TestEqual(TEXT("success read bool"), rootNode->ReadBool(TEXT("root.abc"), true), false); + } + + + // parse ng(string) + { + FString xmlString = TEXT("") + TEXT("") + TEXT("text") + TEXT("") + TEXT(""); + + EEasyXMLParserErrorCode result; + FString errorMessage; + auto rootNode = UEasyXMLParseManager::LoadFromString(xmlString, result, errorMessage); + + + TestEqual(TEXT("ng read bool(string)"), rootNode->ReadBool(TEXT("root.abc"), false), false); + } + + // parse ng(xml) + { + FString xmlString = TEXT("") + TEXT("") + TEXT("") + TEXT("true") + TEXT("") + TEXT("") + TEXT(""); + + EEasyXMLParserErrorCode result; + FString errorMessage; + auto rootNode = UEasyXMLParseManager::LoadFromString(xmlString, result, errorMessage); + + + TestEqual(TEXT("ng read bool(xml)"), rootNode->ReadBool(TEXT("root.abc"), false), false); + } + + return true; +} + + +IMPLEMENT_SIMPLE_AUTOMATION_TEST(FReadValueTest_String, "EasyXMLParser.ReadValueTest.String", EAutomationTestFlags::ApplicationContextMask | EAutomationTestFlags::SmokeFilter) + +bool FReadValueTest_String::RunTest(const FString& Parameters) +{ + // parse success + { + FString xmlString = TEXT("") + TEXT("") + TEXT("text") + TEXT("") + TEXT(""); + + EEasyXMLParserErrorCode result; + FString errorMessage; + auto rootNode = UEasyXMLParseManager::LoadFromString(xmlString, result, errorMessage); + + + TestEqual(TEXT("success read string"), rootNode->ReadString(TEXT("root.abc"), TEXT("")), TEXT("text")); + } + + // parse success + { + FString xmlString = TEXT("") + TEXT("") + TEXT("123") + TEXT("") + TEXT(""); + + EEasyXMLParserErrorCode result; + FString errorMessage; + auto rootNode = UEasyXMLParseManager::LoadFromString(xmlString, result, errorMessage); + + + TestEqual(TEXT("success read string"), rootNode->ReadString(TEXT("root.abc"), TEXT("")), TEXT("123")); + } + + // parse success + { + FString xmlString = TEXT("") + TEXT("") + TEXT("1.23") + TEXT("") + TEXT(""); + + EEasyXMLParserErrorCode result; + FString errorMessage; + auto rootNode = UEasyXMLParseManager::LoadFromString(xmlString, result, errorMessage); + + + TestEqual(TEXT("success read string"), rootNode->ReadString(TEXT("root.abc"), TEXT("")), TEXT("1.23")); + } + + // parse success + { + FString xmlString = TEXT("") + TEXT("") + TEXT("true") + TEXT("") + TEXT(""); + + EEasyXMLParserErrorCode result; + FString errorMessage; + auto rootNode = UEasyXMLParseManager::LoadFromString(xmlString, result, errorMessage); + + + TestEqual(TEXT("success read string"), rootNode->ReadString(TEXT("root.abc"), TEXT("")), TEXT("true")); + } + + // parse success + { + FString xmlString = TEXT("") + TEXT("") + TEXT("false") + TEXT("") + TEXT(""); + + EEasyXMLParserErrorCode result; + FString errorMessage; + auto rootNode = UEasyXMLParseManager::LoadFromString(xmlString, result, errorMessage); + + + TestEqual(TEXT("success read string"), rootNode->ReadString(TEXT("root.abc"), TEXT("")), TEXT("false")); + } + + // parse ng(xml) + { + FString xmlString = TEXT("") + TEXT("") + TEXT("") + TEXT("text") + TEXT("") + TEXT("") + TEXT(""); + + EEasyXMLParserErrorCode result; + FString errorMessage; + auto rootNode = UEasyXMLParseManager::LoadFromString(xmlString, result, errorMessage); + + TestEqual(TEXT("success read string"), rootNode->ReadString(TEXT("root.abc"), TEXT("")), TEXT("")); + } + + return true; +} \ No newline at end of file diff --git a/Plugins/EasyXMLParser/Source/EasyXMLParser/Private/Utils/CustomXMLParser.cpp b/Plugins/EasyXMLParser/Source/EasyXMLParser/Private/Utils/CustomXMLParser.cpp new file mode 100644 index 00000000..935ab95b --- /dev/null +++ b/Plugins/EasyXMLParser/Source/EasyXMLParser/Private/Utils/CustomXMLParser.cpp @@ -0,0 +1,83 @@ +// Copyright 2019 ayumax. All Rights Reserved. +#include "CustomXMLParser.h" + +#include "Misc/FeedbackContext.h" +#include "EasyXMLElement.h" +#include "EasyXMLAttribute.h" + +CustomXMLParser::CustomXMLParser() +{ +} + +CustomXMLParser::~CustomXMLParser() +{ +} + +UEasyXMLElement *CustomXMLParser::Parse(FString xmlString, FString &ErrorMessage) +{ + RootElement = NewObject(); + XMLObjectStack.Emplace(RootElement); + + FText _errorMessage; + int32 _errorMessageNumber; + + if (!FFastXml::ParseXmlFile(this, TEXT(""), &xmlString[0], nullptr, false, false, _errorMessage, _errorMessageNumber)) + { + ErrorMessage = FString::Printf(TEXT("line=%d, %s"), _errorMessageNumber, *_errorMessage.ToString()); + return nullptr; + } + + return RootElement; +} + +bool CustomXMLParser::ProcessXmlDeclaration(const TCHAR *ElementData, int32 XmlFileLineNumber) +{ + return true; +} + +bool CustomXMLParser::ProcessElement(const TCHAR *ElementName, const TCHAR *ElementData, int32 XmlFileLineNumber) +{ + auto currentNode = XMLObjectStack.Num() > 0 ? XMLObjectStack.Last() : nullptr; + + auto newNode = UEasyXMLElement::CreateElement(currentNode, ElementName, ElementData, XmlFileLineNumber); + + if (currentNode) + { + currentNode->Children.Emplace(newNode); + } + + XMLObjectStack.Emplace(newNode); + + return true; +} + +bool CustomXMLParser::ProcessAttribute(const TCHAR *AttributeName, const TCHAR *AttributeValue) +{ + auto currentNode = XMLObjectStack.Last(); + + if (!currentNode) return false; + if (currentNode->Attributes.Contains(AttributeName)) return false; + + auto newAttribute = UEasyXMLAttribute::CreateAttribute(currentNode, AttributeName, AttributeValue); + currentNode->Attributes.Add(AttributeName, newAttribute); + + return true; +} + +bool CustomXMLParser::ProcessClose(const TCHAR *Element) +{ + if (XMLObjectStack.Num() == 0) return false; + + XMLObjectStack.RemoveAt(XMLObjectStack.Num() - 1); + + return true; +} + +bool CustomXMLParser::ProcessComment(const TCHAR *Comment) +{ + if (XMLObjectStack.Num() == 0) return false; + + XMLObjectStack.Last()->Comments.Emplace(Comment); + + return true; +} diff --git a/Plugins/EasyXMLParser/Source/EasyXMLParser/Private/Utils/CustomXMLParser.h b/Plugins/EasyXMLParser/Source/EasyXMLParser/Private/Utils/CustomXMLParser.h new file mode 100644 index 00000000..28545963 --- /dev/null +++ b/Plugins/EasyXMLParser/Source/EasyXMLParser/Private/Utils/CustomXMLParser.h @@ -0,0 +1,68 @@ +// Copyright 2019 ayumax. All Rights Reserved. +#pragma once + +#include "CoreMinimal.h" +#include "FastXml.h" + +class UEasyXMLElement; + +class CustomXMLParser : public IFastXmlCallback +{ +public: + CustomXMLParser(); + virtual ~CustomXMLParser(); + + UEasyXMLElement* Parse(FString xmlString, FString& ErrorMessage); + + /** + * Called after the XML's header is parsed. This is usually the first call that you'll get back. + * + * @param ElementData Optional data for this element, nullptr if none + * @param XmlFileLineNumber Line number in the XML file we're on + * + * @return You should return true to continue processing the file, or false to stop processing immediately. + */ + virtual bool ProcessXmlDeclaration(const TCHAR* ElementData, int32 XmlFileLineNumber) override; + + /** + * Called when a new XML element is encountered, starting a new scope. You'll receive a call to ProcessClose() + * when this element's scope has ended. + * + * @param ElementName The name of the element + * @param ElementData Optional data for this element, nullptr if none + * @param XmlFileLineNumber The line number in the XML file we're on + * + * @return You should return true to continue processing the file, or false to stop processing immediately. + */ + virtual bool ProcessElement(const TCHAR* ElementName, const TCHAR* ElementData, int32 XmlFileLineNumber) override; + + /** + * Called when an XML attribute is encountered for the current scope's element. + * + * @param AttributeName The name of the attribute + * @param AttributeValue The value of the attribute + * + * @return You should return true to continue processing the file, or false to stop processing immediately. + */ + virtual bool ProcessAttribute(const TCHAR* AttributeName, const TCHAR* AttributeValue) override; + + /** + * Called when an element's scope ends in the XML file + * + * @param ElementName Name of the element whose scope closed + * + * @return You should return true to continue processing the file, or false to stop processing immediately. + */ + virtual bool ProcessClose(const TCHAR* Element) override; + + /** + * Called when a comment is encountered. This can happen pretty much anywhere in the file. + * + * @param Comment The comment text + */ + virtual bool ProcessComment(const TCHAR* Comment) override; + +private: + TArray XMLObjectStack; + UEasyXMLElement* RootElement; +}; diff --git a/Plugins/EasyXMLParser/Source/EasyXMLParser/Public/EasyXMLAsyncLoadFromFile.h b/Plugins/EasyXMLParser/Source/EasyXMLParser/Public/EasyXMLAsyncLoadFromFile.h new file mode 100644 index 00000000..51b93e81 --- /dev/null +++ b/Plugins/EasyXMLParser/Source/EasyXMLParser/Public/EasyXMLAsyncLoadFromFile.h @@ -0,0 +1,40 @@ +// Copyright 2019 ayumax. All Rights Reserved. +#pragma once + +#include "CoreMinimal.h" +#include "Kismet/BlueprintAsyncActionBase.h" +#include "UObject/NoExportTypes.h" +#include "EasyXMLElement.h" +#include "EasyXMLAsyncLoadFromFile.generated.h" + +DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FEasyXMLAsyncLoadFromFile_Result, UEasyXMLElement*, XMLObject, FString, ErrorMessage); + + +UCLASS() +class EASYXMLPARSER_API UEasyXMLAsyncLoadFromFile : public UBlueprintAsyncActionBase +{ + GENERATED_BODY() + +public: + UPROPERTY(BlueprintAssignable) + FEasyXMLAsyncLoadFromFile_Result Successed; + + UPROPERTY(BlueprintAssignable) + FEasyXMLAsyncLoadFromFile_Result Failed; + +private: + UPROPERTY(Transient) + FString _XMLFile; + UPROPERTY(Transient) + bool _IsAblolute; + +public: + UEasyXMLAsyncLoadFromFile(const FObjectInitializer& ObjectInitializer); + + UFUNCTION(BlueprintCallable, Category = "EasyXMLParser", meta = (WorldContext = "WorldContextObject", BlueprintInternalUseOnly = "true")) + static UEasyXMLAsyncLoadFromFile * AsyncLoadFromFile(UObject * WorldContextObject, const FString& FilePath, bool IsAblolute); + + + virtual void Activate() override; + +}; \ No newline at end of file diff --git a/Plugins/EasyXMLParser/Source/EasyXMLParser/Public/EasyXMLAsyncLoadFromString.h b/Plugins/EasyXMLParser/Source/EasyXMLParser/Public/EasyXMLAsyncLoadFromString.h new file mode 100644 index 00000000..ebfa3872 --- /dev/null +++ b/Plugins/EasyXMLParser/Source/EasyXMLParser/Public/EasyXMLAsyncLoadFromString.h @@ -0,0 +1,38 @@ +// Copyright 2019 ayumax. All Rights Reserved. +#pragma once + +#include "CoreMinimal.h" +#include "Kismet/BlueprintAsyncActionBase.h" +#include "UObject/NoExportTypes.h" +#include "EasyXMLElement.h" +#include "EasyXMLAsyncLoadFromString.generated.h" + +DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FEasyXMLAsyncLoadFromString_Result, UEasyXMLElement*, XMLObject, FString, ErrorMessage); + + +UCLASS() +class EASYXMLPARSER_API UEasyXMLAsyncLoadFromString : public UBlueprintAsyncActionBase +{ + GENERATED_BODY() + +public: + UPROPERTY(BlueprintAssignable) + FEasyXMLAsyncLoadFromString_Result Successed; + + UPROPERTY(BlueprintAssignable) + FEasyXMLAsyncLoadFromString_Result Failed; + +private: + UPROPERTY(Transient) + FString _XMLString; + +public: + UEasyXMLAsyncLoadFromString(const FObjectInitializer& ObjectInitializer); + + UFUNCTION(BlueprintCallable, Category = "EasyXMLParser", meta = (WorldContext = "WorldContextObject", BlueprintInternalUseOnly = "true")) + static UEasyXMLAsyncLoadFromString* AsyncLoadFromString(UObject * WorldContextObject, const FString& XMLString); + + + virtual void Activate() override; + +}; \ No newline at end of file diff --git a/Plugins/EasyXMLParser/Source/EasyXMLParser/Public/EasyXMLAttribute.h b/Plugins/EasyXMLParser/Source/EasyXMLParser/Public/EasyXMLAttribute.h new file mode 100644 index 00000000..a89ebe49 --- /dev/null +++ b/Plugins/EasyXMLParser/Source/EasyXMLParser/Public/EasyXMLAttribute.h @@ -0,0 +1,18 @@ +// Copyright 2019 ayumax. All Rights Reserved. +#pragma once + +#include "CoreMinimal.h" +#include "EasyXMLObject.h" +#include "EasyXMLAttribute.generated.h" + +class UEasyXMLElement; + +UCLASS(BlueprintType, Blueprintable) +class EASYXMLPARSER_API UEasyXMLAttribute : public UEasyXMLObject +{ + GENERATED_BODY() + +public: + static UEasyXMLAttribute* CreateAttribute(UEasyXMLElement* ParentObject, FString Name, FString Value); + +}; diff --git a/Plugins/EasyXMLParser/Source/EasyXMLParser/Public/EasyXMLElement.h b/Plugins/EasyXMLParser/Source/EasyXMLParser/Public/EasyXMLElement.h new file mode 100644 index 00000000..c00af7e4 --- /dev/null +++ b/Plugins/EasyXMLParser/Source/EasyXMLParser/Public/EasyXMLElement.h @@ -0,0 +1,62 @@ +// Copyright 2019 ayumax. All Rights Reserved. +#pragma once + +#include "EasyXMLObject.h" +#include "EasyXMLParserEnums.h" +#include "EasyXMLElement.generated.h" + +class UEasyXMLAttribute; + +UCLASS(BlueprintType, Blueprintable) +class EASYXMLPARSER_API UEasyXMLElement : public UEasyXMLObject +{ + GENERATED_BODY() + +public: + static UEasyXMLElement* CreateElement(UEasyXMLObject* ParentObject, FString Tag, FString Content, int32 LineNumber); + +public: + UFUNCTION(BlueprintPure, Category = "EasyXMLParser|ReadValue") + int32 ReadInt(const FString& AccessString, int32 DefaultValue = 0); + + UFUNCTION(BlueprintPure, Category = "EasyXMLParser|ReadValue") + float ReadFloat(const FString& AccessString, float DefaultValue = 0.0f); + + UFUNCTION(BlueprintPure, Category = "EasyXMLParser|ReadValue") + FString ReadString(const FString& AccessString, const FString& DefaultValue = TEXT("")); + + UFUNCTION(BlueprintPure, Category = "EasyXMLParser|ReadValue") + bool ReadBool(const FString& AccessString, bool DefaultValue = false); + + UFUNCTION(BlueprintCallable, Category = "EasyXMLParser|ReadValue", meta = (ExpandEnumAsExecs = "Result")) + UEasyXMLElement* ReadElement(const FString& AccessString, EEasyXMLParserFound& Result); + + UFUNCTION(BlueprintCallable, Category = "EasyXMLParser|ReadValue", meta = (ExpandEnumAsExecs = "Result")) + TArray ReadElements(const FString& AccessString, EEasyXMLParserFound& Result); + + UFUNCTION(BlueprintPure, Category = "EasyXMLParser|Object", meta = (ExpandEnumAsExecs = "Result")) + UEasyXMLAttribute* GetAttribute(const FString& AtrributeName, EEasyXMLParserFound& Result); + + +public: + UEasyXMLObject* ReadEasyXMLObject(const FString& AccessString); + TArray GetElementsByTagName(const FString& TagName); + bool IsContainAttributeKeys(const TArray& Keys, TArray& FoundAttributeKeys); + +private: + bool IsAccessAsArray(const FString& AccessName, FString& ElementName, int32& ArrayIndex); + + +public: + UPROPERTY(BlueprintReadOnly, Category = "EasyXMLParser|Object") + int32 LineNumber = 0; + + UPROPERTY(BlueprintReadOnly, Category = "EasyXMLParser|Object") + TArray Children; + + UPROPERTY(BlueprintReadOnly, Category = "EasyXMLParser|Object") + TMap Attributes; + + UPROPERTY(BlueprintReadOnly, Category = "EasyXMLParser|Object") + TArray Comments; +}; diff --git a/Plugins/EasyXMLParser/Source/EasyXMLParser/Public/EasyXMLObject.h b/Plugins/EasyXMLParser/Source/EasyXMLParser/Public/EasyXMLObject.h new file mode 100644 index 00000000..f1196515 --- /dev/null +++ b/Plugins/EasyXMLParser/Source/EasyXMLParser/Public/EasyXMLObject.h @@ -0,0 +1,37 @@ +// Copyright 2019 ayumax. All Rights Reserved. +#pragma once + +#include "CoreMinimal.h" +#include "UObject/NoExportTypes.h" +#include "EasyXMLObject.generated.h" + + +UCLASS(BlueprintType, Blueprintable) +class EASYXMLPARSER_API UEasyXMLObject : public UObject +{ + GENERATED_BODY() + +public: + UFUNCTION(BlueprintPure, Category = "EasyXMLParser|GetValue") + int32 GetIntValue(int32 DefaultValue = 0); + + UFUNCTION(BlueprintPure, Category = "EasyXMLParser|GetValue") + float GetFloatValue(float DefaultValue = 0.0f); + + UFUNCTION(BlueprintPure, Category = "EasyXMLParser|GetValue") + FString GetStringValue(FString DefaultValue = TEXT("")); + + UFUNCTION(BlueprintPure, Category = "EasyXMLParser|GetValue") + bool GetBoolValue(bool DefaultValue = false); + +public: + UPROPERTY(BlueprintReadOnly, Category = "EasyXMLParser|Object") + FString Name = TEXT(""); + + UPROPERTY(BlueprintReadOnly, Category = "EasyXMLParser|Object") + FString Value = TEXT(""); + + UPROPERTY(BlueprintReadOnly, Category = "EasyXMLParser|Object") + UEasyXMLObject* Parent = nullptr; + +}; diff --git a/Plugins/EasyXMLParser/Source/EasyXMLParser/Public/EasyXMLParseManager.h b/Plugins/EasyXMLParser/Source/EasyXMLParser/Public/EasyXMLParseManager.h new file mode 100644 index 00000000..5c653471 --- /dev/null +++ b/Plugins/EasyXMLParser/Source/EasyXMLParser/Public/EasyXMLParseManager.h @@ -0,0 +1,36 @@ +// Copyright 2019 ayumax. All Rights Reserved. +#pragma once + +#include "CoreMinimal.h" +#include "UObject/NoExportTypes.h" +#include "EasyXMLElement.h" +#include "EasyXMLParserEnums.h" +#include "EasyXMLParseManager.generated.h" + +/** + * + */ +UCLASS(BlueprintType, Blueprintable) +class EASYXMLPARSER_API UEasyXMLParseManager : public UObject +{ + GENERATED_BODY() + +public: + /** + * load xml file + * @param FilePath - xml file path + * @param IsAblolute - true:FilePath is absolute path, false:Relative path from "Content" + * @return xml object + */ + UFUNCTION(BlueprintCallable, Category = "EasyXMLParser", meta = (ExpandEnumAsExecs = "Result")) + static UEasyXMLElement* LoadFromFile(const FString& FilePath, bool IsAblolute, EEasyXMLParserErrorCode& Result, FString& ErrorMessage); + + /** + * load xml string + * @param XMLString - xml file path + * @return xml object + */ + UFUNCTION(BlueprintCallable, Category = "EasyXMLParser", meta = (ExpandEnumAsExecs = "Result")) + static UEasyXMLElement* LoadFromString(const FString& XMLString, EEasyXMLParserErrorCode& Result, FString& ErrorMessage); + +}; diff --git a/Plugins/EasyXMLParser/Source/EasyXMLParser/Public/EasyXMLParser.h b/Plugins/EasyXMLParser/Source/EasyXMLParser/Public/EasyXMLParser.h new file mode 100644 index 00000000..2a386922 --- /dev/null +++ b/Plugins/EasyXMLParser/Source/EasyXMLParser/Public/EasyXMLParser.h @@ -0,0 +1,15 @@ +// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" +#include "Modules/ModuleManager.h" + +class FEasyXMLParserModule : public IModuleInterface +{ +public: + + /** IModuleInterface implementation */ + virtual void StartupModule() override; + virtual void ShutdownModule() override; +}; diff --git a/Plugins/EasyXMLParser/Source/EasyXMLParser/Public/EasyXMLParserEnums.h b/Plugins/EasyXMLParser/Source/EasyXMLParser/Public/EasyXMLParserEnums.h new file mode 100644 index 00000000..f3edc900 --- /dev/null +++ b/Plugins/EasyXMLParser/Source/EasyXMLParser/Public/EasyXMLParserEnums.h @@ -0,0 +1,19 @@ +// Copyright 2019 ayumax. All Rights Reserved. + +#pragma once + +#include "CoreMinimal.h" + +UENUM(BlueprintType) +enum class EEasyXMLParserErrorCode : uint8 +{ + Successed, + Failed +}; + +UENUM(BlueprintType) +enum class EEasyXMLParserFound : uint8 +{ + Found, + NotFound +}; \ No newline at end of file diff --git a/Plugins/JPrinter/Binaries/Win64/UnrealEditor-JPrinter.dll b/Plugins/JPrinter/Binaries/Win64/UnrealEditor-JPrinter.dll new file mode 100644 index 00000000..11e827cf Binary files /dev/null and b/Plugins/JPrinter/Binaries/Win64/UnrealEditor-JPrinter.dll differ diff --git a/Plugins/JPrinter/Binaries/Win64/UnrealEditor.modules b/Plugins/JPrinter/Binaries/Win64/UnrealEditor.modules new file mode 100644 index 00000000..24fed7df --- /dev/null +++ b/Plugins/JPrinter/Binaries/Win64/UnrealEditor.modules @@ -0,0 +1,7 @@ +{ + "BuildId": "23058290", + "Modules": + { + "JPrinter": "UnrealEditor-JPrinter.dll" + } +} \ No newline at end of file diff --git a/Plugins/JPrinter/JPrinter.uplugin b/Plugins/JPrinter/JPrinter.uplugin new file mode 100644 index 00000000..980a408c --- /dev/null +++ b/Plugins/JPrinter/JPrinter.uplugin @@ -0,0 +1,23 @@ +{ + "FileVersion": 3, + "Version": 1, + "VersionName": "1.0", + "FriendlyName": "JPrinter", + "Description": "Now you can print picture from unreal direcly!, you print from file or even print a texture, only for windows, soon mac ox", + "Category": "Hardware", + "CreatedBy": "ZKarmaKun", + "CreatedByURL": "", + "DocsURL": "", + "MarketplaceURL": "", + "SupportURL": "", + "EngineVersion": "5.1.0", + "CanContainContent": false, + "Installed": true, + "Modules": [ + { + "Name": "JPrinter", + "Type": "Runtime", + "LoadingPhase": "Default" + } + ] +} \ No newline at end of file diff --git a/Plugins/JPrinter/Resources/Icon128.png b/Plugins/JPrinter/Resources/Icon128.png new file mode 100644 index 00000000..1228ddbd Binary files /dev/null and b/Plugins/JPrinter/Resources/Icon128.png differ diff --git a/Plugins/JPrinter/Source/JPrinter/JPrinter.Build.cs b/Plugins/JPrinter/Source/JPrinter/JPrinter.Build.cs new file mode 100644 index 00000000..7f4696f4 --- /dev/null +++ b/Plugins/JPrinter/Source/JPrinter/JPrinter.Build.cs @@ -0,0 +1,69 @@ +// Some copyright should be here... + +using UnrealBuildTool; +using System.IO; + +public class JPrinter : ModuleRules +{ + public JPrinter(ReadOnlyTargetRules Target): base( Target ) + { + + PublicIncludePaths.AddRange( + new string[] { + "JPrinter/Public" + + // ... add public include paths required here ... + } + ); + + + PrivateIncludePaths.AddRange( + new string[] { + "JPrinter/Private", + + // ... add other private include paths required here ... + } + ); + + + PublicDependencyModuleNames.AddRange( + new string[] + { + "Core", + + // ... add other public dependencies that you statically link with here ... + } + ); + + + PrivateDependencyModuleNames.AddRange( + new string[] + { + "CoreUObject", + "Engine", + "Slate", + "SlateCore", + "ImageWrapper", + // ... add private dependencies that you statically link with here ... + } + ); + + + DynamicallyLoadedModuleNames.AddRange( + new string[] + { + // ... add any modules that your module loads dynamically here ... + } + ); + + //string ModulePath = Path.GetDirectoryName(RulesCompiler.GetModuleFilename(this.GetType().Name)); + /* + string ThirdParty = Path.GetFullPath(Path.Combine(ModuleDirectory, "../../ThirdParty/")); + + string IncludePaths = Path.Combine(ThirdParty, "opencv", "include"); + string LibPath = Path.Combine(ThirdParty, "opencv", "lib"); + PublicIncludePaths.Add(IncludePaths); + PublicAdditionalLibraries.Add(LibPath + "/opencv_world300.lib"); + PublicAdditionalLibraries.Add(LibPath + "/opencv_ts300.lib");*/ + } +} diff --git a/Plugins/JPrinter/Source/JPrinter/Private/JPrinter.cpp b/Plugins/JPrinter/Source/JPrinter/Private/JPrinter.cpp new file mode 100644 index 00000000..e6cfc9ec --- /dev/null +++ b/Plugins/JPrinter/Source/JPrinter/Private/JPrinter.cpp @@ -0,0 +1,22 @@ +// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. +#include "JPrinter.h" +#include "JPrinterPrivatePCH.h" + +#define LOCTEXT_NAMESPACE "FJPrinterModule" + +void FJPrinterModule::StartupModule() +{ + // This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module + +} + +void FJPrinterModule::ShutdownModule() +{ + // This function may be called during shutdown to clean up your module. For modules that support dynamic reloading, + // we call this function before unloading the module. + +} + +#undef LOCTEXT_NAMESPACE + +IMPLEMENT_MODULE(FJPrinterModule, JPrinter) \ No newline at end of file diff --git a/Plugins/JPrinter/Source/JPrinter/Private/JPrinterBPLibrary.cpp b/Plugins/JPrinter/Source/JPrinter/Private/JPrinterBPLibrary.cpp new file mode 100644 index 00000000..0a8f0da9 --- /dev/null +++ b/Plugins/JPrinter/Source/JPrinter/Private/JPrinterBPLibrary.cpp @@ -0,0 +1,266 @@ +// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. +#include "JPrinterBPLibrary.h" +#include "JPrinterPrivatePCH.h" + +#define print(txt) GEngine->AddOnScreenDebugMessage(-1,10,FColor::Green, txt) +DEFINE_LOG_CATEGORY_STATIC(JPrinterLog, Log, All); + +UJPrinterBPLibrary::UJPrinterBPLibrary(const FObjectInitializer& ObjectInitializer) +: Super(ObjectInitializer) +{ + +} + +TArray UJPrinterBPLibrary::getPrinterList() +{ + TArray out; +#if PLATFORM_WINDOWS + LPBYTE pPrinterEnum; + unsigned long pcbNeeded, pcbReturned; + PRINTER_INFO_2* printerInfo = NULL; + EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 2, NULL, 0, &pcbNeeded, &pcbReturned); + + pPrinterEnum = new BYTE[pcbNeeded]; + if (EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 2, pPrinterEnum, pcbNeeded, &pcbNeeded, &pcbReturned)) + { + printerInfo = ((PRINTER_INFO_2*)pPrinterEnum); + for (unsigned short i = 0; i < pcbReturned; i++) + { + TCHAR* wname = printerInfo[i].pPrinterName; + FString name = wname; + out.Add(name); + } + } +#endif + return out; +} + +FString UJPrinterBPLibrary::getPrimaryPrinterName() +{ + FString out; +#if PLATFORM_WINDOWS + unsigned long size = 0; + GetDefaultPrinter(NULL, &size); + if (size) + { + TCHAR* buffer = new TCHAR[size]; + GetDefaultPrinter(buffer, &size); + out = buffer; + } +#endif + return out; +} + +#if PLATFORM_WINDOWS +printerInfo UJPrinterBPLibrary::getPrinterInfo(FString printer, bool usePrimary) +{ + printerInfo out; + unsigned long size = 0; + LPWSTR defaultName = NULL; + GetDefaultPrinter(NULL, &size); + if (size) + { + TCHAR* buffer = new TCHAR[size]; + GetDefaultPrinter(buffer, &size); + defaultName = buffer; + } + + if (defaultName) + { + out.deviceName = defaultName; + LPBYTE pPrinterEnum; + unsigned long pcbNeeded, pcbReturned; + PRINTER_INFO_2* printerInfo = NULL; + EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 2, NULL, 0, &pcbNeeded, &pcbReturned); + + pPrinterEnum = new BYTE[pcbNeeded]; + if (EnumPrinters(PRINTER_ENUM_LOCAL, NULL, 2, pPrinterEnum, pcbNeeded, &pcbNeeded, &pcbReturned)) + { + printerInfo = ((PRINTER_INFO_2*)pPrinterEnum); + std::wstring wsdefaultName(defaultName); + std::string sdefaultName(wsdefaultName.begin(), wsdefaultName.end()); + + for (unsigned int i = 0; i < pcbReturned; i++) + { + LPWSTR name = printerInfo[i].pPrinterName; + std::wstring wsname(name); + std::string sname(wsname.begin(), wsname.end()); + if (usePrimary) + { + if (sname == sdefaultName) + { + out.driver = printerInfo[i].pDriverName; + out.portName = printerInfo[i].pPortName; + } + } + else + { + std::string choosen(TCHAR_TO_ANSI(*printer)); + if (sname == choosen) + { + out.driver = printerInfo[i].pDriverName; + out.portName = printerInfo[i].pPortName; + } + } + + } + } + } + return out; +} + +HBITMAP UJPrinterBPLibrary::getHBITMAPFromData(TArray& bgraData, int32 width, int32 height, int32 bitDepth) +{ + if (bgraData.Num() <= 0) return NULL; + + uint8* rgb = new uint8[width * height * 3]; + for (int i = 0; i < (width * height); i++) + { + rgb[3 * i + 0] = bgraData[i].B; + rgb[3 * i + 1] = bgraData[i].G; + rgb[3 * i + 2] = bgraData[i].R; + } + // Create DIB + HBITMAP hbmp = CreateBitmap(width, height, 1, 24, rgb); + if (hbmp == NULL) { + delete rgb; + return hbmp; + } + delete rgb; + return hbmp; +} +#endif + +FString UJPrinterBPLibrary::Replace(FString source, FString in, FString out) +{ + TArray ar = source.GetCharArray(); + FString result; + for (int i = 0; i < ar.Num(); i++) + { + if (ar[i] != in[0]) + { + result += ar[i]; + } + else + { + result += out; + } + } + return result; +} + +bool UJPrinterBPLibrary::printImage(FString path, FString printer, bool usePrimary) +{ + if (!FPaths::FileExists(path)) { + UE_LOG(JPrinterLog, Log, TEXT("%s"), *path) + return false; + } + + if (usePrimary) + { + printer = getPrimaryPrinterName(); + } + + path = "\"" + path + "\""; + path = Replace(path, "/", "\\"); + FString args = " c:\\WINDOWS\\system32\\shimgvw.dll,ImageView_PrintTo /pt " + path + " \"" + printer + "\""; + FString prg = "rundll32"; + UE_LOG(JPrinterLog, Log, TEXT("%s%s"), *prg,*args); + int error=33; //= WinExec(TCHAR_TO_ANSI(*fullPath), SW_SHOW); + FPlatformProcess::CreateProc( + *prg, + *args, + false,//* @param bLaunchDetached if true, the new process will have its own window + false,//* @param bLaunchHidded if true, the new process will be minimized in the task bar + false,//* @param bLaunchReallyHidden if true, the new process will not have a window or be in the task bar + 0, + 0, + nullptr,//const TCHAR* OptionalWorkingDirectory, + nullptr + ); + return (error == 33) ? true : false; +} + +bool UJPrinterBPLibrary::printTexture2D(UTexture2D* texture, FString printer, bool usePrimary, EPaperSize paperSize) +{ + if (!texture) return false; + + //const double DPIConvertion = 142.0643729189789; + //const float DPIConvertion = 142.0643729189789f; + const float DPIConvertion = 142.06437f; + + bool out = false; + int32 width = texture->GetSizeX(); + int32 height = texture->GetSizeY(); + int32 bitDepth = 24; + TArray colorData; + colorData.Init(FColor(), width * height); + FTexture2DMipMap& Mip = texture->PlatformData->Mips[0]; + uint8* Data = (uint8*)Mip.BulkData.Lock(LOCK_READ_WRITE); + + for (int i = 0; i < colorData.Num(); i++) + { + colorData[i].R = Data[4 * i + 2]; + colorData[i].G = Data[4 * i + 1]; + colorData[i].B = Data[4 * i + 0]; + colorData[i].A = 255; + } + + Mip.BulkData.Unlock(); + texture->UpdateResource(); + + if (paperSize != EPaperSize::None) + { + + float scale = 1; + switch (paperSize) + { + case EPaperSize::letter: + if (width == 2969) break; + scale = FMath::FloorToFloat((2969.f / width) * 100) / 100.f; + break; + case EPaperSize::photo: + if (width == 1373) break; + scale = FMath::FloorToFloat((1373.f / width) * 1000) / 1000.f; + break; + default: + break; + } + + if (scale != 1) + { + TArray fixColorData; + FImageUtils::ImageResize(width, height, colorData, width * scale, height * scale, fixColorData, true); + width = width * scale; + height = height * scale; + colorData = fixColorData; + } + + } + +#if PLATFORM_WINDOWS + HWND currentWindow = GetActiveWindow(); + printerInfo dev = getPrinterInfo(printer, usePrimary); + + HBITMAP hBMP = getHBITMAPFromData(colorData, width, height, bitDepth); + //HBITMAP hBMP = (HBITMAP)LoadImage(NULL, L"D:/gokuHQ.bmp", IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE); + HDC printerHDC = CreateDC(dev.driver, dev.deviceName, dev.portName, NULL); + if (printerHDC) + { + HDC hdc = CreateCompatibleDC(printerHDC); + SelectObject(hdc, hBMP); + Escape(printerHDC, STARTDOC, 8, "Happy-Doc", NULL); + BitBlt(printerHDC, 0, 0, width, height, hdc, 0, 0, SRCCOPY2); + Escape(printerHDC, NEWFRAME, 0, NULL, NULL); + Escape(printerHDC, ENDDOC, 0, NULL, NULL); + + UE_LOG(JPrinterLog,Log, TEXT("Printing... wPX=%i hPX=%i"), width, height); + + DeleteDC(printerHDC); + out = true; + } + +#endif + + return out; +} diff --git a/Plugins/JPrinter/Source/JPrinter/Private/JPrinterPrivatePCH.h b/Plugins/JPrinter/Source/JPrinter/Private/JPrinterPrivatePCH.h new file mode 100644 index 00000000..e3704763 --- /dev/null +++ b/Plugins/JPrinter/Source/JPrinter/Private/JPrinterPrivatePCH.h @@ -0,0 +1,6 @@ +// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. + +#include "JPrinter.h" + +// You should place include statements to your module's private header files here. You only need to +// add includes for headers that are used in most of your module's source files though. \ No newline at end of file diff --git a/Plugins/JPrinter/Source/JPrinter/Public/JPrinter.h b/Plugins/JPrinter/Source/JPrinter/Public/JPrinter.h new file mode 100644 index 00000000..92ae5ce4 --- /dev/null +++ b/Plugins/JPrinter/Source/JPrinter/Public/JPrinter.h @@ -0,0 +1,14 @@ +// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "Modules/ModuleManager.h" + +class FJPrinterModule : public IModuleInterface +{ +public: + + /** IModuleInterface implementation */ + virtual void StartupModule() override; + virtual void ShutdownModule() override; +}; \ No newline at end of file diff --git a/Plugins/JPrinter/Source/JPrinter/Public/JPrinterBPLibrary.h b/Plugins/JPrinter/Source/JPrinter/Public/JPrinterBPLibrary.h new file mode 100644 index 00000000..418a9fc8 --- /dev/null +++ b/Plugins/JPrinter/Source/JPrinter/Public/JPrinterBPLibrary.h @@ -0,0 +1,69 @@ +// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved. + +#pragma once +#if PLATFORM_WINDOWS +#include "Windows/AllowWindowsPlatformTypes.h" +#include "Windows.h" +#include "winspool.h" +#include "iostream" +#include "time.h" +#include "fstream" +#include "string" +#include "Windows/HideWindowsPlatformTypes.h" +#endif +#include "Engine.h" +#include "ImageUtils.h" + +//opencv +//#include "opencv/cv.hpp" + +#include "JPrinterBPLibrary.generated.h" + +//using namespace cv; + +#if PLATFORM_WINDOWS +struct printerInfo +{ + LPCWSTR portName; + LPCWSTR driver; + LPCWSTR deviceName; + LPCWSTR output = NULL; +}; +#define SRCCOPY2 (unsigned long)0x00CC0020 +#endif + +UENUM(BlueprintType) +enum class EPaperSize : uint8 +{ + None UMETA(DisplayName = "None"), + letter UMETA(DisplayName = "Letter 8 1/2 x 11 in"), + photo UMETA(DisplayName = "Photo 4 x 6 in"), +}; + +UCLASS() +class UJPrinterBPLibrary : public UBlueprintFunctionLibrary +{ + GENERATED_UCLASS_BODY() + +public: + UFUNCTION(BlueprintPure, Category = JPrinter) + static TArray getPrinterList(); + + UFUNCTION(BlueprintPure, Category = JPrinter) + static FString getPrimaryPrinterName(); + + UFUNCTION(BlueprintCallable, Category = JPrinter) + static bool printImage(FString path, FString printer, bool usePrimary = true); + + UFUNCTION(BlueprintCallable, Category = JPrinter) + static bool printTexture2D(UTexture2D* texture, FString printer, bool usePrimary, EPaperSize paperSize = EPaperSize::None); + + + static FString Replace(FString source, FString in, FString out); + +#if PLATFORM_WINDOWS + static printerInfo getPrinterInfo(FString printer, bool usePrimary); + static HBITMAP getHBITMAPFromData(TArray& bgraData, int32 width, int32 height, int32 bitDepth); +#endif + +}; diff --git a/Plugins/createProcess/Binaries/Win64/UnrealEditor-createProcess.dll b/Plugins/createProcess/Binaries/Win64/UnrealEditor-createProcess.dll new file mode 100644 index 00000000..32c5b2bd Binary files /dev/null and b/Plugins/createProcess/Binaries/Win64/UnrealEditor-createProcess.dll differ diff --git a/Plugins/createProcess/Binaries/Win64/UnrealEditor-createProcess.pdb b/Plugins/createProcess/Binaries/Win64/UnrealEditor-createProcess.pdb new file mode 100644 index 00000000..d3fd7fe1 Binary files /dev/null and b/Plugins/createProcess/Binaries/Win64/UnrealEditor-createProcess.pdb differ diff --git a/Plugins/createProcess/Binaries/Win64/UnrealEditor.modules b/Plugins/createProcess/Binaries/Win64/UnrealEditor.modules new file mode 100644 index 00000000..4a376be8 --- /dev/null +++ b/Plugins/createProcess/Binaries/Win64/UnrealEditor.modules @@ -0,0 +1,7 @@ +{ + "BuildId": "23058290", + "Modules": + { + "createProcess": "UnrealEditor-createProcess.dll" + } +} \ No newline at end of file diff --git a/Plugins/createProcess/Resources/Icon128.png b/Plugins/createProcess/Resources/Icon128.png new file mode 100644 index 00000000..ba509b9e Binary files /dev/null and b/Plugins/createProcess/Resources/Icon128.png differ diff --git a/Plugins/createProcess/Source/createProcess/Private/createProcess.cpp b/Plugins/createProcess/Source/createProcess/Private/createProcess.cpp new file mode 100644 index 00000000..967ea2e8 --- /dev/null +++ b/Plugins/createProcess/Source/createProcess/Private/createProcess.cpp @@ -0,0 +1,22 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "createProcess.h" + +#define LOCTEXT_NAMESPACE "FcreateProcessModule" + +void FcreateProcessModule::StartupModule() +{ + // This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module + +} + +void FcreateProcessModule::ShutdownModule() +{ + // This function may be called during shutdown to clean up your module. For modules that support dynamic reloading, + // we call this function before unloading the module. + +} + +#undef LOCTEXT_NAMESPACE + +IMPLEMENT_MODULE(FcreateProcessModule, createProcess) \ No newline at end of file diff --git a/Plugins/createProcess/Source/createProcess/Private/createProcessBPLibrary.cpp b/Plugins/createProcess/Source/createProcess/Private/createProcessBPLibrary.cpp new file mode 100644 index 00000000..0aa6cad2 --- /dev/null +++ b/Plugins/createProcess/Source/createProcess/Private/createProcessBPLibrary.cpp @@ -0,0 +1,46 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "createProcessBPLibrary.h" +#include "createProcess.h" + +UcreateProcessBPLibrary::UcreateProcessBPLibrary(const FObjectInitializer& ObjectInitializer) +: Super(ObjectInitializer) +{ + +} + +void UcreateProcessBPLibrary::createProc(FString FullPathOfProgramToRun, TArray CommandlineArgs, bool Detach, bool Hidden, int32 Priority, FString OptionalWorkingDirectory) +{ //Please note ProcessId should really be uint32 but that is not supported by BP yet + + FString Args = ""; + if (CommandlineArgs.Num() > 1) + { + Args = CommandlineArgs[0]; + for (int32 v = 1; v < CommandlineArgs.Num(); v++) + { + Args += " " + CommandlineArgs[v]; + } + } + else if (CommandlineArgs.Num() > 0) + { + Args = CommandlineArgs[0]; + } + + //uint32 NeedBPUINT32 = 0; + FPlatformProcess::CreateProc( + *FullPathOfProgramToRun, + *Args, + Detach,//* @param bLaunchDetached if true, the new process will have its own window + false,//* @param bLaunchHidded if true, the new process will be minimized in the task bar + Hidden,//* @param bLaunchReallyHidden if true, the new process will not have a window or be in the task bar + 0, + Priority, + (OptionalWorkingDirectory != "") ? *OptionalWorkingDirectory : nullptr,//const TCHAR* OptionalWorkingDirectory, + nullptr + ); +} + +void UcreateProcessBPLibrary::RunSystemCommand(FString Command) +{ + system(TCHAR_TO_ANSI(*Command)); +} \ No newline at end of file diff --git a/Plugins/createProcess/Source/createProcess/Public/createProcess.h b/Plugins/createProcess/Source/createProcess/Public/createProcess.h new file mode 100644 index 00000000..235bde46 --- /dev/null +++ b/Plugins/createProcess/Source/createProcess/Public/createProcess.h @@ -0,0 +1,14 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "Modules/ModuleManager.h" + +class FcreateProcessModule : public IModuleInterface +{ +public: + + /** IModuleInterface implementation */ + virtual void StartupModule() override; + virtual void ShutdownModule() override; +}; diff --git a/Plugins/createProcess/Source/createProcess/Public/createProcessBPLibrary.h b/Plugins/createProcess/Source/createProcess/Public/createProcessBPLibrary.h new file mode 100644 index 00000000..3744edf8 --- /dev/null +++ b/Plugins/createProcess/Source/createProcess/Public/createProcessBPLibrary.h @@ -0,0 +1,36 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "Kismet/BlueprintFunctionLibrary.h" +#include "GenericPlatform/GenericPlatformProcess.h" +#include "createProcessBPLibrary.generated.h" + +/* +* Function library class. +* Each function in it is expected to be static and represents blueprint node that can be called in any blueprint. +* +* When declaring function you can define metadata for the node. Key function specifiers will be BlueprintPure and BlueprintCallable. +* BlueprintPure - means the function does not affect the owning object in any way and thus creates a node without Exec pins. +* BlueprintCallable - makes a function which can be executed in Blueprints - Thus it has Exec pins. +* DisplayName - full name of the node, shown when you mouse over the node and in the blueprint drop down menu. +* Its lets you name the node using characters not allowed in C++ function names. +* CompactNodeTitle - the word(s) that appear on the node. +* Keywords - the list of keywords that helps you to find node when you search for it using Blueprint drop-down menu. +* Good example is "Print String" node which you can find also by using keyword "log". +* Category - the category your node will be under in the Blueprint drop-down menu. +* +* For more info on custom blueprint nodes visit documentation: +* https://wiki.unrealengine.com/Custom_Blueprint_Node_Creation +*/ +UCLASS() +class UcreateProcessBPLibrary : public UBlueprintFunctionLibrary +{ + GENERATED_UCLASS_BODY() + + + UFUNCTION(BlueprintCallable, Category = "createProcess") + static void createProc(FString FullPathOfProgramToRun, TArray CommandlineArgs, bool Detach, bool Hidden, int32 Priority, FString OptionalWorkingDirectory); + UFUNCTION(BlueprintCallable, Category = "createProcess") + static void RunSystemCommand(FString Command); +}; diff --git a/Plugins/createProcess/Source/createProcess/createProcess.Build.cs b/Plugins/createProcess/Source/createProcess/createProcess.Build.cs new file mode 100644 index 00000000..0d968f6b --- /dev/null +++ b/Plugins/createProcess/Source/createProcess/createProcess.Build.cs @@ -0,0 +1,53 @@ +// Some copyright should be here... + +using UnrealBuildTool; + +public class createProcess : ModuleRules +{ + public createProcess(ReadOnlyTargetRules Target) : base(Target) + { + PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; + + PublicIncludePaths.AddRange( + new string[] { + // ... add public include paths required here ... + } + ); + + + PrivateIncludePaths.AddRange( + new string[] { + // ... add other private include paths required here ... + } + ); + + + PublicDependencyModuleNames.AddRange( + new string[] + { + "Core", + // ... add other public dependencies that you statically link with here ... + } + ); + + + PrivateDependencyModuleNames.AddRange( + new string[] + { + "CoreUObject", + "Engine", + "Slate", + "SlateCore", + // ... add private dependencies that you statically link with here ... + } + ); + + + DynamicallyLoadedModuleNames.AddRange( + new string[] + { + // ... add any modules that your module loads dynamically here ... + } + ); + } +} diff --git a/Plugins/createProcess/createProcess.uplugin b/Plugins/createProcess/createProcess.uplugin new file mode 100644 index 00000000..0651c540 --- /dev/null +++ b/Plugins/createProcess/createProcess.uplugin @@ -0,0 +1,26 @@ +{ + "FileVersion": 3, + "Version": 1, + "VersionName": "1.0", + "FriendlyName": "createProcess", + "Description": "", + "Category": "Process", + "CreatedBy": "Dron", + "CreatedByURL": "", + "DocsURL": "", + "MarketplaceURL": "", + "SupportURL": "", + "EngineVersion": "5.1.0", + "CanContainContent": false, + "Installed": true, + "Modules": [ + { + "Name": "createProcess", + "Type": "Runtime", + "LoadingPhase": "PostEngineInit", + "WhitelistPlatforms": [ + "Win64" + ] + } + ] +} \ No newline at end of file diff --git a/Plugins/manageTextFile/Binaries/Win64/UnrealEditor-manageTextFile.dll b/Plugins/manageTextFile/Binaries/Win64/UnrealEditor-manageTextFile.dll new file mode 100644 index 00000000..c12a0083 Binary files /dev/null and b/Plugins/manageTextFile/Binaries/Win64/UnrealEditor-manageTextFile.dll differ diff --git a/Plugins/manageTextFile/Binaries/Win64/UnrealEditor-manageTextFile.pdb b/Plugins/manageTextFile/Binaries/Win64/UnrealEditor-manageTextFile.pdb new file mode 100644 index 00000000..10db8a6a Binary files /dev/null and b/Plugins/manageTextFile/Binaries/Win64/UnrealEditor-manageTextFile.pdb differ diff --git a/Plugins/manageTextFile/Binaries/Win64/UnrealEditor.modules b/Plugins/manageTextFile/Binaries/Win64/UnrealEditor.modules new file mode 100644 index 00000000..daa9cddb --- /dev/null +++ b/Plugins/manageTextFile/Binaries/Win64/UnrealEditor.modules @@ -0,0 +1,7 @@ +{ + "BuildId": "23058290", + "Modules": + { + "manageTextFile": "UnrealEditor-manageTextFile.dll" + } +} \ No newline at end of file diff --git a/Plugins/manageTextFile/Resources/Icon128.png b/Plugins/manageTextFile/Resources/Icon128.png new file mode 100644 index 00000000..88e72fc5 Binary files /dev/null and b/Plugins/manageTextFile/Resources/Icon128.png differ diff --git a/Plugins/manageTextFile/Source/manageTextFile/Private/manageTextFile.cpp b/Plugins/manageTextFile/Source/manageTextFile/Private/manageTextFile.cpp new file mode 100644 index 00000000..3141dfcd --- /dev/null +++ b/Plugins/manageTextFile/Source/manageTextFile/Private/manageTextFile.cpp @@ -0,0 +1,22 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "manageTextFile.h" + +#define LOCTEXT_NAMESPACE "FmanageTextFileModule" + +void FmanageTextFileModule::StartupModule() +{ + // This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module + +} + +void FmanageTextFileModule::ShutdownModule() +{ + // This function may be called during shutdown to clean up your module. For modules that support dynamic reloading, + // we call this function before unloading the module. + +} + +#undef LOCTEXT_NAMESPACE + +IMPLEMENT_MODULE(FmanageTextFileModule, manageTextFile) \ No newline at end of file diff --git a/Plugins/manageTextFile/Source/manageTextFile/Private/manageTextFileBPLibrary.cpp b/Plugins/manageTextFile/Source/manageTextFile/Private/manageTextFileBPLibrary.cpp new file mode 100644 index 00000000..1a397434 --- /dev/null +++ b/Plugins/manageTextFile/Source/manageTextFile/Private/manageTextFileBPLibrary.cpp @@ -0,0 +1,75 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#include "manageTextFileBPLibrary.h" +#include "manageTextFile.h" + +UmanageTextFileBPLibrary::UmanageTextFileBPLibrary(const FObjectInitializer& ObjectInitializer) +: Super(ObjectInitializer) +{ + +} + +bool UmanageTextFileBPLibrary::CreateTextFile(FString Path, FString FileName, FString Text) +{ + if (Path == "" || FileName == "") { + UE_LOG(LogTemp, Warning, TEXT("Empty Path or FileName, aborting")); + return false; + } + Path.ReplaceInline(TEXT("/"), TEXT("\\")); + FString fullpath(Path + "\\" + FileName); + return FFileHelper::SaveStringToFile(Text, *fullpath, FFileHelper::EEncodingOptions::ForceUTF8); +} + +bool UmanageTextFileBPLibrary::AppendStringToFile(FString Path, FString FileName, FString Text) +{ + if (Path == "" || FileName == "") { + UE_LOG(LogTemp, Warning, TEXT("Empty Path or FileName, aborting")); + return false; + } + Path.ReplaceInline(TEXT("/"), TEXT("\\")); + FString fullpath(Path + "\\" + FileName); + + FString OldText; + if (FPaths::FileExists(fullpath)) + { + FFileHelper::LoadFileToString(OldText, *fullpath); + OldText += Text; + return FFileHelper::SaveStringToFile(Text, *fullpath, FFileHelper::EEncodingOptions::ForceUTF8, &IFileManager::Get(), FILEWRITE_Append); + } + else + { + return CreateTextFile(Path, FileName, Text); + } +} + +bool UmanageTextFileBPLibrary::FileExists(FString Path, FString FileName) +{ + if (Path == "" || FileName == "") { + UE_LOG(LogTemp, Warning, TEXT("Empty Path or FileName, aborting")); + return false; + } + Path.ReplaceInline(TEXT("/"), TEXT("\\")); + return FPaths::FileExists(Path + "\\" + FileName); +} + +bool UmanageTextFileBPLibrary::DeleteFile(FString Path, FString FileName) +{ + if (Path == "" || FileName == "") { + UE_LOG(LogTemp, Warning, TEXT("Empty Path or FileName, aborting")); + return false; + } + Path.ReplaceInline(TEXT("/"), TEXT("\\")); + FString fullpath = Path + "\\" + FileName; + return FPlatformFileManager::Get().GetPlatformFile().DeleteFile(*fullpath); +} + +bool UmanageTextFileBPLibrary::readFile(FString Path, FString FileName,FString &Str) { + if (Path == "" || FileName == "") { + UE_LOG(LogTemp, Warning, TEXT("Empty Path or FileName, aborting")); + return false; + } + + FString fullpath = Path + "\\" + FileName; + return FFileHelper::LoadFileToString(Str, *fullpath); + +} \ No newline at end of file diff --git a/Plugins/manageTextFile/Source/manageTextFile/Public/manageTextFile.h b/Plugins/manageTextFile/Source/manageTextFile/Public/manageTextFile.h new file mode 100644 index 00000000..6b8536c8 --- /dev/null +++ b/Plugins/manageTextFile/Source/manageTextFile/Public/manageTextFile.h @@ -0,0 +1,14 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "Modules/ModuleManager.h" + +class FmanageTextFileModule : public IModuleInterface +{ +public: + + /** IModuleInterface implementation */ + virtual void StartupModule() override; + virtual void ShutdownModule() override; +}; diff --git a/Plugins/manageTextFile/Source/manageTextFile/Public/manageTextFileBPLibrary.h b/Plugins/manageTextFile/Source/manageTextFile/Public/manageTextFileBPLibrary.h new file mode 100644 index 00000000..ec551b09 --- /dev/null +++ b/Plugins/manageTextFile/Source/manageTextFile/Public/manageTextFileBPLibrary.h @@ -0,0 +1,43 @@ +// Copyright Epic Games, Inc. All Rights Reserved. + +#pragma once + +#include "Kismet/BlueprintFunctionLibrary.h" +#include "Misc/FileHelper.h" +#include "Misc/Paths.h" +#include "HAL/PlatformFilemanager.h" +#include "manageTextFileBPLibrary.generated.h" + +/* +* Function library class. +* Each function in it is expected to be static and represents blueprint node that can be called in any blueprint. +* +* When declaring function you can define metadata for the node. Key function specifiers will be BlueprintPure and BlueprintCallable. +* BlueprintPure - means the function does not affect the owning object in any way and thus creates a node without Exec pins. +* BlueprintCallable - makes a function which can be executed in Blueprints - Thus it has Exec pins. +* DisplayName - full name of the node, shown when you mouse over the node and in the blueprint drop down menu. +* Its lets you name the node using characters not allowed in C++ function names. +* CompactNodeTitle - the word(s) that appear on the node. +* Keywords - the list of keywords that helps you to find node when you search for it using Blueprint drop-down menu. +* Good example is "Print String" node which you can find also by using keyword "log". +* Category - the category your node will be under in the Blueprint drop-down menu. +* +* For more info on custom blueprint nodes visit documentation: +* https://wiki.unrealengine.com/Custom_Blueprint_Node_Creation +*/ +UCLASS() +class UmanageTextFileBPLibrary : public UBlueprintFunctionLibrary +{ + GENERATED_UCLASS_BODY() + + UFUNCTION(BlueprintCallable, Category = "manageTextFile") + static bool CreateTextFile(FString Path, FString FileName, FString Text); + UFUNCTION(BlueprintCallable, Category = "manageTextFile") + static bool AppendStringToFile(FString Path, FString FileName, FString Text); + UFUNCTION(BlueprintCallable, Category = "manageTextFile") + static bool FileExists(FString Path, FString FileName); + UFUNCTION(BlueprintCallable, Category = "manageTextFile") + static bool DeleteFile(FString Path, FString FileName); + UFUNCTION(BlueprintCallable, Category = "manageTextFile") + static bool readFile(FString Path, FString FileName, FString & Str); +}; diff --git a/Plugins/manageTextFile/Source/manageTextFile/manageTextFile.Build.cs b/Plugins/manageTextFile/Source/manageTextFile/manageTextFile.Build.cs new file mode 100644 index 00000000..7fc57590 --- /dev/null +++ b/Plugins/manageTextFile/Source/manageTextFile/manageTextFile.Build.cs @@ -0,0 +1,53 @@ +// Some copyright should be here... + +using UnrealBuildTool; + +public class manageTextFile : ModuleRules +{ + public manageTextFile(ReadOnlyTargetRules Target) : base(Target) + { + PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs; + + PublicIncludePaths.AddRange( + new string[] { + // ... add public include paths required here ... + } + ); + + + PrivateIncludePaths.AddRange( + new string[] { + // ... add other private include paths required here ... + } + ); + + + PublicDependencyModuleNames.AddRange( + new string[] + { + "Core", + // ... add other public dependencies that you statically link with here ... + } + ); + + + PrivateDependencyModuleNames.AddRange( + new string[] + { + "CoreUObject", + "Engine", + "Slate", + "SlateCore", + // ... add private dependencies that you statically link with here ... + } + ); + + + DynamicallyLoadedModuleNames.AddRange( + new string[] + { + // ... add any modules that your module loads dynamically here ... + } + ); + } +} diff --git a/Plugins/manageTextFile/manageTextFile.uplugin b/Plugins/manageTextFile/manageTextFile.uplugin new file mode 100644 index 00000000..d2bc7954 --- /dev/null +++ b/Plugins/manageTextFile/manageTextFile.uplugin @@ -0,0 +1,25 @@ +{ + "FileVersion": 3, + "Version": 1, + "VersionName": "1.0", + "FriendlyName": "manageTextFile", + "Description": "", + "Category": "fileIO", + "CreatedBy": "Dron", + "CreatedByURL": "", + "DocsURL": "", + "MarketplaceURL": "", + "SupportURL": "", + "CanContainContent": false, + "Installed": true, + "Modules": [ + { + "Name": "manageTextFile", + "Type": "Runtime", + "LoadingPhase": "PostEngineInit", + "WhitelistPlatforms": [ + "Win64" + ] + } + ] +} \ No newline at end of file