Ready for the first beta release. #105

Merged
That-One-Nerd merged 41 commits from main-canary into main 2023-05-18 13:05:42 -04:00
13 changed files with 101 additions and 102 deletions
Showing only changes of commit 856811687e - Show all commits

View File

@ -1,6 +0,0 @@
namespace SrcMod.Shell.Valve.ObjectModels;
public interface IVdfConvertible
{
public VdfNode ToNodeTree();
}

View File

@ -1,8 +0,0 @@
namespace SrcMod.Shell.Valve.ObjectModels;
public class VdfSerializationException : Exception
{
public VdfSerializationException() : base() { }
public VdfSerializationException(string message) : base(message) { }
public VdfSerializationException(string message, Exception inner) : base(message, inner) { }
}

View File

@ -1,6 +0,0 @@
namespace SrcMod.Shell.Valve;
public abstract class VdfNode
{
}

View File

@ -1,11 +0,0 @@
namespace SrcMod.Shell.Valve;
public class VdfSingleNode : VdfNode
{
public object? value;
public VdfSingleNode(object? value = null) : base()
{
this.value = value;
}
}

View File

@ -0,0 +1,8 @@
using SrcMod.Shell.Valve.Vkv;
namespace SrcMod.Shell.Valve.Vkv.ObjectModels;
public interface IVkvConvertible
{
public VkvNode ToNodeTree();
}

View File

@ -1,4 +1,4 @@
namespace SrcMod.Shell.Valve.ObjectModels; namespace SrcMod.Shell.Valve.Vkv.ObjectModels;
[AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = true)] [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
public class VdfIgnoreAttribute : Attribute { } public class VkvIgnoreAttribute : Attribute { }

View File

@ -0,0 +1,8 @@
namespace SrcMod.Shell.Valve.Vkv.ObjectModels;
public class VkvSerializationException : Exception
{
public VkvSerializationException() : base() { }
public VkvSerializationException(string message) : base(message) { }
public VkvSerializationException(string message, Exception inner) : base(message, inner) { }
}

View File

@ -1,8 +1,8 @@
using SrcMod.Shell.Valve.ObjectModels; using SrcMod.Shell.Valve.Vkv.ObjectModels;
namespace SrcMod.Shell.Valve; namespace SrcMod.Shell.Valve.Vkv;
public static class VdfConvert public static class VkvConvert
{ {
private static readonly Dictionary<string, string> p_escapeCodes = new() private static readonly Dictionary<string, string> p_escapeCodes = new()
{ {
@ -20,12 +20,12 @@ public static class VdfConvert
}; };
#region DeserializeNode #region DeserializeNode
public static VdfNode? DeserializeNode(StreamReader reader) => public static VkvNode? DeserializeNode(StreamReader reader) =>
DeserializeNode(reader, VdfOptions.Default, out _, null); DeserializeNode(reader, VkvOptions.Default, out _, null);
public static VdfNode? DeserializeNode(StreamReader reader, VdfOptions options) => public static VkvNode? DeserializeNode(StreamReader reader, VkvOptions options) =>
DeserializeNode(reader, options, out _, null); DeserializeNode(reader, options, out _, null);
private static VdfNode? DeserializeNode(StreamReader reader, VdfOptions options, out string name, private static VkvNode? DeserializeNode(StreamReader reader, VkvOptions options, out string name,
string? first) string? first)
{ {
string? header = first ?? (reader.ReadLine()?.Trim()); string? header = first ?? (reader.ReadLine()?.Trim());
@ -36,31 +36,31 @@ public static class VdfConvert
} }
string[] parts = SplitContent(header, options); string[] parts = SplitContent(header, options);
if (parts.Length > 2) throw new VdfSerializationException("Too many values in node."); if (parts.Length > 2) throw new VkvSerializationException("Too many values in node.");
VdfNode node; VkvNode node;
name = DeserializeString(parts[0], options); name = DeserializeString(parts[0], options);
if (parts.Length == 2) if (parts.Length == 2)
{ {
object value = DeserializeObject(DeserializeString(parts[1], options)); object value = DeserializeObject(DeserializeString(parts[1], options));
node = new VdfSingleNode(value); node = new VkvSingleNode(value);
} }
else else
{ {
string? next = reader.ReadLine()?.Trim(); string? next = reader.ReadLine()?.Trim();
if (next is null) throw new VdfSerializationException("Expected starting '{', found end-of-file."); if (next is null) throw new VkvSerializationException("Expected starting '{', found end-of-file.");
else if (next != "{") throw new VdfSerializationException($"Expected starting '{{', found \"{next}\"."); else if (next != "{") throw new VkvSerializationException($"Expected starting '{{', found \"{next}\".");
VdfTreeNode tree = new(); VkvTreeNode tree = new();
string? current; string? current;
while ((current = reader.ReadLine()?.Trim()) is not null) while ((current = reader.ReadLine()?.Trim()) is not null)
{ {
if (current == "}") break; if (current == "}") break;
VdfNode? output = DeserializeNode(reader, options, out string subName, current); VkvNode? output = DeserializeNode(reader, options, out string subName, current);
if (output is null) throw new VdfSerializationException("Error deserializing sub-node."); if (output is null) throw new VkvSerializationException("Error deserializing sub-node.");
tree[subName] = output; tree[subName] = output;
} }
if (current is null) throw new VdfSerializationException("Reached end-of-file while deserializing group."); if (current is null) throw new VkvSerializationException("Reached end-of-file while deserializing group.");
node = tree; node = tree;
} }
@ -69,12 +69,12 @@ public static class VdfConvert
private static object DeserializeObject(string content) => private static object DeserializeObject(string content) =>
TypeParsers.ParseAll(content); TypeParsers.ParseAll(content);
private static string DeserializeString(string content, VdfOptions options) private static string DeserializeString(string content, VkvOptions options)
{ {
if (options.useQuotes) if (options.useQuotes)
{ {
if (!content.StartsWith('\"') || !content.EndsWith('\"')) if (!content.StartsWith('\"') || !content.EndsWith('\"'))
throw new VdfSerializationException("No quotes found around content."); throw new VkvSerializationException("No quotes found around content.");
content = content[1..^1]; content = content[1..^1];
} }
if (options.useEscapeCodes) if (options.useEscapeCodes)
@ -85,7 +85,7 @@ public static class VdfConvert
return content; return content;
} }
private static string[] SplitContent(string content, VdfOptions options) private static string[] SplitContent(string content, VkvOptions options)
{ {
content = content.Replace('\t', ' '); content = content.Replace('\t', ' ');
if (options.useQuotes) if (options.useQuotes)
@ -105,7 +105,7 @@ public static class VdfConvert
} }
else current += c; else current += c;
} }
if (inQuote) throw new VdfSerializationException("Reached end-of-line while inside quotations."); if (inQuote) throw new VkvSerializationException("Reached end-of-line while inside quotations.");
if (!string.IsNullOrEmpty(current)) values.Add(current); if (!string.IsNullOrEmpty(current)) values.Add(current);
return values.ToArray(); return values.ToArray();
} }
@ -114,7 +114,7 @@ public static class VdfConvert
#endregion #endregion
#region FromNodeTree #region FromNodeTree
public static object? FromNodeTree(Type outputType, VdfNode? node, VdfOptions options) public static object? FromNodeTree(Type outputType, VkvNode? node, VkvOptions options)
{ {
if (node is null) return null; if (node is null) return null;
@ -125,7 +125,7 @@ public static class VdfConvert
let isPublic = field.IsPublic let isPublic = field.IsPublic
let isStatic = field.IsStatic let isStatic = field.IsStatic
let isIgnored = field.CustomAttributes.Any(x => let isIgnored = field.CustomAttributes.Any(x =>
x.AttributeType == typeof(VdfIgnoreAttribute)) x.AttributeType == typeof(VkvIgnoreAttribute))
let isConst = field.IsLiteral let isConst = field.IsLiteral
where isPublic && !isStatic && !isIgnored && !isConst where isPublic && !isStatic && !isIgnored && !isConst
select field; select field;
@ -138,7 +138,7 @@ public static class VdfConvert
let isPublic = canSet && prop.SetMethod!.IsPublic let isPublic = canSet && prop.SetMethod!.IsPublic
let isStatic = canSet && prop.SetMethod!.IsStatic let isStatic = canSet && prop.SetMethod!.IsStatic
let isIgnored = prop.CustomAttributes.Any(x => let isIgnored = prop.CustomAttributes.Any(x =>
x.AttributeType == typeof(VdfIgnoreAttribute)) x.AttributeType == typeof(VkvIgnoreAttribute))
where canSet && isPublic && !isStatic && !isIgnored where canSet && isPublic && !isStatic && !isIgnored
select prop; select prop;
} }
@ -151,7 +151,7 @@ public static class VdfConvert
Type castType = field.FieldType; Type castType = field.FieldType;
if (TypeParsers.CanParse(instance)) if (TypeParsers.CanParse(instance))
{ {
} }
} }
foreach (PropertyInfo prop in validProperties) foreach (PropertyInfo prop in validProperties)
@ -170,22 +170,22 @@ public static class VdfConvert
#endregion #endregion
#region SerializeNode #region SerializeNode
public static void SerializeNode(StreamWriter writer, VdfNode? node, string name, public static void SerializeNode(StreamWriter writer, VkvNode? node, string name,
VdfOptions options) => SerializeNode(writer, node, name, options, 0); VkvOptions options) => SerializeNode(writer, node, name, options, 0);
public static void SerializeNode(StreamWriter writer, VdfNode? node, string name) => public static void SerializeNode(StreamWriter writer, VkvNode? node, string name) =>
SerializeNode(writer, node, name, VdfOptions.Default, 0); SerializeNode(writer, node, name, VkvOptions.Default, 0);
private static void SerializeNode(StreamWriter writer, VdfNode? node, string name, private static void SerializeNode(StreamWriter writer, VkvNode? node, string name,
VdfOptions options, int indentLevel) VkvOptions options, int indentLevel)
{ {
if (node is null) return; if (node is null) return;
else if (node is VdfSingleNode single) SerializeSingleNode(writer, single, name, options, indentLevel); else if (node is VkvSingleNode single) SerializeSingleNode(writer, single, name, options, indentLevel);
else if (node is VdfTreeNode tree) SerializeTreeNode(writer, tree, name, options, indentLevel); else if (node is VkvTreeNode tree) SerializeTreeNode(writer, tree, name, options, indentLevel);
else throw new("Unknown node type."); else throw new("Unknown node type.");
} }
private static void SerializeSingleNode(StreamWriter writer, VdfSingleNode node, string name, private static void SerializeSingleNode(StreamWriter writer, VkvSingleNode node, string name,
VdfOptions options, int indentLevel) VkvOptions options, int indentLevel)
{ {
string? serializedValue = SerializeObject(node.value); string? serializedValue = SerializeObject(node.value);
if (serializedValue is null) return; if (serializedValue is null) return;
@ -197,8 +197,8 @@ public static class VdfConvert
serializedValue = SerializeString(serializedValue, options); serializedValue = SerializeString(serializedValue, options);
writer.WriteLine(serializedValue); writer.WriteLine(serializedValue);
} }
private static void SerializeTreeNode(StreamWriter writer, VdfTreeNode node, string name, private static void SerializeTreeNode(StreamWriter writer, VkvTreeNode node, string name,
VdfOptions options, int indentLevel) VkvOptions options, int indentLevel)
{ {
if (node.SubNodeCount <= 0) return; if (node.SubNodeCount <= 0) return;
@ -206,7 +206,7 @@ public static class VdfConvert
writer.WriteLine(SerializeString(name, options)); writer.WriteLine(SerializeString(name, options));
writer.WriteLine(new string(' ', indentLevel) + '{'); writer.WriteLine(new string(' ', indentLevel) + '{');
foreach (KeyValuePair<string, VdfNode?> subNode in node) foreach (KeyValuePair<string, VkvNode?> subNode in node)
SerializeNode(writer, subNode.Value, subNode.Key, options, indentLevel + options.indentSize); SerializeNode(writer, subNode.Value, subNode.Key, options, indentLevel + options.indentSize);
writer.WriteLine(new string(' ', indentLevel) + '}'); writer.WriteLine(new string(' ', indentLevel) + '}');
@ -218,7 +218,7 @@ public static class VdfConvert
return obj.ToString() ?? string.Empty; return obj.ToString() ?? string.Empty;
} }
private static string SerializeString(string content, VdfOptions options) private static string SerializeString(string content, VkvOptions options)
{ {
if (options.useEscapeCodes) if (options.useEscapeCodes)
{ {
@ -232,18 +232,18 @@ public static class VdfConvert
#endregion #endregion
#region ToNodeTree #region ToNodeTree
public static VdfNode? ToNodeTree(object? obj) => ToNodeTree(obj, VdfOptions.Default); public static VkvNode? ToNodeTree(object? obj) => ToNodeTree(obj, VkvOptions.Default);
public static VdfNode? ToNodeTree(object? obj, VdfOptions options) public static VkvNode? ToNodeTree(object? obj, VkvOptions options)
{ {
if (obj is null) return null; if (obj is null) return null;
Type type = obj.GetType(); Type type = obj.GetType();
if (type.IsPrimitive || TypeParsers.CanParse(obj)) return new VdfSingleNode(obj); if (type.IsPrimitive || TypeParsers.CanParse(obj)) return new VkvSingleNode(obj);
else if (type.IsPointer) throw new("Cannot serialize a pointer."); else if (type.IsPointer) throw new("Cannot serialize a pointer.");
VdfTreeNode tree = new(); VkvTreeNode tree = new();
if (obj is IVdfConvertible vdf) return vdf.ToNodeTree(); if (obj is IVkvConvertible vdf) return vdf.ToNodeTree();
else if (obj is IDictionary dictionary) else if (obj is IDictionary dictionary)
{ {
object[] keys = new object[dictionary.Count], object[] keys = new object[dictionary.Count],
@ -271,7 +271,7 @@ public static class VdfConvert
let isPublic = field.IsPublic let isPublic = field.IsPublic
let isStatic = field.IsStatic let isStatic = field.IsStatic
let isIgnored = field.CustomAttributes.Any(x => let isIgnored = field.CustomAttributes.Any(x =>
x.AttributeType == typeof(VdfIgnoreAttribute)) x.AttributeType == typeof(VkvIgnoreAttribute))
let isConst = field.IsLiteral let isConst = field.IsLiteral
where isPublic && !isStatic && !isIgnored && !isConst where isPublic && !isStatic && !isIgnored && !isConst
select field; select field;
@ -284,7 +284,7 @@ public static class VdfConvert
let isPublic = canGet && prop.GetMethod!.IsPublic let isPublic = canGet && prop.GetMethod!.IsPublic
let isStatic = canGet && prop.GetMethod!.IsStatic let isStatic = canGet && prop.GetMethod!.IsStatic
let isIgnored = prop.CustomAttributes.Any(x => let isIgnored = prop.CustomAttributes.Any(x =>
x.AttributeType == typeof(VdfIgnoreAttribute)) x.AttributeType == typeof(VkvIgnoreAttribute))
where canGet && isPublic && !isStatic && !isIgnored where canGet && isPublic && !isStatic && !isIgnored
select prop; select prop;
} }

View File

@ -0,0 +1,3 @@
namespace SrcMod.Shell.Valve.Vkv;
public abstract class VkvNode { }

View File

@ -1,8 +1,8 @@
namespace SrcMod.Shell.Valve; namespace SrcMod.Shell.Valve.Vkv;
public record class VdfOptions public record class VkvOptions
{ {
public static VdfOptions Default => new(); public static VkvOptions Default => new();
public bool closeWhenFinished; public bool closeWhenFinished;
public int indentSize; public int indentSize;
@ -11,7 +11,7 @@ public record class VdfOptions
public bool useEscapeCodes; public bool useEscapeCodes;
public bool useQuotes; public bool useQuotes;
public VdfOptions() public VkvOptions()
{ {
closeWhenFinished = true; closeWhenFinished = true;
indentSize = 4; indentSize = 4;

View File

@ -1,22 +1,22 @@
namespace SrcMod.Shell.Valve; namespace SrcMod.Shell.Valve.Vkv;
public class VdfSerializer public class VkvSerializer
{ {
public VdfOptions Options => p_options; public VkvOptions Options => p_options;
private readonly VdfOptions p_options; private readonly VkvOptions p_options;
public VdfSerializer() : this(VdfOptions.Default) { } public VkvSerializer() : this(VkvOptions.Default) { }
public VdfSerializer(VdfOptions options) public VkvSerializer(VkvOptions options)
{ {
p_options = options; p_options = options;
} }
public VdfNode? Deserialize(Stream stream) public VkvNode? Deserialize(Stream stream)
{ {
long pos = stream.Position; long pos = stream.Position;
StreamReader reader = new(stream, leaveOpen: !p_options.closeWhenFinished); StreamReader reader = new(stream, leaveOpen: !p_options.closeWhenFinished);
VdfNode? result = VdfConvert.DeserializeNode(reader, p_options); VkvNode? result = VkvConvert.DeserializeNode(reader, p_options);
reader.Close(); reader.Close();
if (!p_options.closeWhenFinished && p_options.resetStreamPosition) stream.Seek(pos, SeekOrigin.Begin); if (!p_options.closeWhenFinished && p_options.resetStreamPosition) stream.Seek(pos, SeekOrigin.Begin);
@ -25,14 +25,14 @@ public class VdfSerializer
public void Serialize(Stream stream, object? value, string parentNodeName) public void Serialize(Stream stream, object? value, string parentNodeName)
{ {
VdfNode? nodeTree = VdfConvert.ToNodeTree(value, p_options); VkvNode? nodeTree = VkvConvert.ToNodeTree(value, p_options);
Serialize(stream, nodeTree, parentNodeName); Serialize(stream, nodeTree, parentNodeName);
} }
public void Serialize(Stream stream, VdfNode? parentNode, string parentNodeName) public void Serialize(Stream stream, VkvNode? parentNode, string parentNodeName)
{ {
long pos = stream.Position; long pos = stream.Position;
StreamWriter writer = new(stream, leaveOpen: !p_options.closeWhenFinished); StreamWriter writer = new(stream, leaveOpen: !p_options.closeWhenFinished);
VdfConvert.SerializeNode(writer, parentNode, parentNodeName, p_options); VkvConvert.SerializeNode(writer, parentNode, parentNodeName, p_options);
writer.Close(); writer.Close();
if (!p_options.closeWhenFinished && p_options.resetStreamPosition) stream.Seek(pos, SeekOrigin.Begin); if (!p_options.closeWhenFinished && p_options.resetStreamPosition) stream.Seek(pos, SeekOrigin.Begin);

View File

@ -0,0 +1,11 @@
namespace SrcMod.Shell.Valve.Vkv;
public class VkvSingleNode : VkvNode
{
public object? value;
public VkvSingleNode(object? value = null) : base()
{
this.value = value;
}
}

View File

@ -1,21 +1,21 @@
namespace SrcMod.Shell.Valve; namespace SrcMod.Shell.Valve.Vkv;
public class VdfTreeNode : VdfNode, IEnumerable<KeyValuePair<string, VdfNode?>> public class VkvTreeNode : VkvNode, IEnumerable<KeyValuePair<string, VkvNode?>>
{ {
public int SubNodeCount => p_subNodes.Count; public int SubNodeCount => p_subNodes.Count;
private readonly Dictionary<string, VdfNode?> p_subNodes; private readonly Dictionary<string, VkvNode?> p_subNodes;
public VdfTreeNode(Dictionary<string, VdfNode?>? subNodes = null) : base() public VkvTreeNode(Dictionary<string, VkvNode?>? subNodes = null) : base()
{ {
p_subNodes = subNodes ?? new(); p_subNodes = subNodes ?? new();
} }
public VdfNode? this[string key] public VkvNode? this[string key]
{ {
get get
{ {
if (p_subNodes.TryGetValue(key, out VdfNode? value)) return value; if (p_subNodes.TryGetValue(key, out VkvNode? value)) return value;
else return null; else return null;
} }
set set
@ -24,7 +24,7 @@ public class VdfTreeNode : VdfNode, IEnumerable<KeyValuePair<string, VdfNode?>>
else p_subNodes.Add(key, value); else p_subNodes.Add(key, value);
} }
} }
public VdfNode? this[int index] public VkvNode? this[int index]
{ {
get get
{ {
@ -38,8 +38,8 @@ public class VdfTreeNode : VdfNode, IEnumerable<KeyValuePair<string, VdfNode?>>
} }
} }
public void Add(string key, VdfNode? value) => this[key] = value; public void Add(string key, VkvNode? value) => this[key] = value;
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator(); IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
public IEnumerator<KeyValuePair<string, VdfNode?>> GetEnumerator() => p_subNodes.GetEnumerator(); public IEnumerator<KeyValuePair<string, VkvNode?>> GetEnumerator() => p_subNodes.GetEnumerator();
} }