From 7c96f30d1b47ceaa8e8c49f2c3b261e3e7b255a5 Mon Sep 17 00:00:00 2001 From: That_One_Nerd Date: Wed, 10 May 2023 13:34:22 -0400 Subject: [PATCH] Finished VKV deserialization development :) --- SrcMod/Valve.NET/Vkv/VkvConvert.cs | 43 ++++++++++++++++++++++----- SrcMod/Valve.NET/Vkv/VkvSerializer.cs | 10 +++++++ 2 files changed, 46 insertions(+), 7 deletions(-) diff --git a/SrcMod/Valve.NET/Vkv/VkvConvert.cs b/SrcMod/Valve.NET/Vkv/VkvConvert.cs index 2b8c4d2..dad6678 100644 --- a/SrcMod/Valve.NET/Vkv/VkvConvert.cs +++ b/SrcMod/Valve.NET/Vkv/VkvConvert.cs @@ -1,7 +1,4 @@ -using System; -using Valve.Vkv.ObjectModels; - -using ValveParsers = Valve.Miscellaneous.TypeParsers; +using Valve.Vkv.ObjectModels; namespace Valve.Vkv; @@ -115,6 +112,7 @@ public static class VkvConvert #endregion #region FromNodeTree + public static T? FromNodeTree(VkvNode? node, VkvOptions options) => (T?)FromNodeTree(typeof(T), node, options); public static object? FromNodeTree(Type outputType, VkvNode? node, VkvOptions options) { if (node is null) return null; @@ -130,7 +128,7 @@ public static class VkvConvert if (value is null) return null; else if (value is string str) { - value = ValveParsers.ParseAll(str); + value = TypeParsers.ParseAll(str); if (value is string still && outputType.IsEnum) { if (Enum.TryParse(outputType, still, true, out object? res) && res is not null) @@ -148,6 +146,9 @@ public static class VkvConvert else if (outputType.GetInterface("IList") is not null) return FromTreeNodeList(outputType, node, options); + else if (outputType.GetInterface("IDictionary") is not null) + return FromTreeNodeDictionary(outputType, node, options); + object? instance = Activator.CreateInstance(outputType); if (instance is null) return null; @@ -223,7 +224,7 @@ public static class VkvConvert // There is no guarentee that the first type argument corresponds to the element type, // but as far as I know there isn't a better way. - Type elementType = outputType.IsGenericType ? outputType.GetGenericArguments().First() : typeof(object); + Type elementType = outputType.IsGenericType ? outputType.GenericTypeArguments[0] : typeof(object); int index = 0; foreach (KeyValuePair subNode in node) @@ -235,6 +236,34 @@ public static class VkvConvert } return instance; } + + private static object? FromTreeNodeDictionary(Type outputType, VkvTreeNode node, VkvOptions options) + { + IDictionary? instance = (IDictionary?)Activator.CreateInstance(outputType); + if (instance is null) return null; + + // There is no guarentee that the first and second type arguments represent the + // key and value types, but as far as I know there isn't a better way. + bool canUseGenerics = outputType.GenericTypeArguments.Length >= 2; + Type keyType = canUseGenerics ? outputType.GenericTypeArguments[0] : typeof(object), + valueType = canUseGenerics ? outputType.GenericTypeArguments[1] : typeof(object); + + foreach (KeyValuePair subNode in node) + { + object key = TypeParsers.ParseAll(subNode.Key); + if (key is string still && keyType.IsEnum) + { + if (Enum.TryParse(keyType, still, true, out object? res) && res is not null) + key = res; + } + key = Convert.ChangeType(key, keyType); + + object? value = FromNodeTree(valueType, subNode.Value, options); + + instance.Add(key, value); + } + return instance; + } #endregion #region SerializeNode @@ -306,7 +335,7 @@ public static class VkvConvert if (obj is null) return null; Type type = obj.GetType(); - if (type.IsPrimitive || ValveParsers.CanParse(obj)) return new VkvSingleNode(obj); + if (type.IsPrimitive || TypeParsers.CanParse(obj)) return new VkvSingleNode(obj); else if (type.IsPointer) throw new("Cannot serialize a pointer."); VkvTreeNode tree = new(); diff --git a/SrcMod/Valve.NET/Vkv/VkvSerializer.cs b/SrcMod/Valve.NET/Vkv/VkvSerializer.cs index 0724a0a..135845b 100644 --- a/SrcMod/Valve.NET/Vkv/VkvSerializer.cs +++ b/SrcMod/Valve.NET/Vkv/VkvSerializer.cs @@ -22,6 +22,16 @@ public class VkvSerializer if (!p_options.closeWhenFinished && p_options.resetStreamPosition) stream.Seek(pos, SeekOrigin.Begin); return result; } + public T? Deserialize(Stream stream) + { + VkvNode? result = Deserialize(stream); + return VkvConvert.FromNodeTree(result, p_options); + } + public object? Deserialize(Type outputType, Stream stream) + { + VkvNode? result = Deserialize(stream); + return VkvConvert.FromNodeTree(outputType, result, p_options); + } public void Serialize(Stream stream, object? value, string parentNodeName) {